├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── Procfile ├── README.md ├── app.json ├── dev ├── externs │ └── highlight.js ├── public │ ├── assets │ │ ├── carousel.png │ │ ├── logo.png │ │ └── style.css │ └── vendor │ │ ├── bootstrap │ │ ├── bootstrap.css │ │ └── docs.css │ │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ │ └── highlight │ │ ├── highlight.pack.js │ │ └── solarized.css └── snippets │ ├── alert │ └── basic.cljs │ ├── badge.cljs │ ├── button │ ├── active.cljs │ ├── block.cljs │ ├── disabled.cljs │ ├── dropdown_basic.cljs │ ├── dropdown_sizes.cljs │ ├── group.cljs │ ├── group_basic.cljs │ ├── group_justified.cljs │ ├── group_nested.cljs │ ├── group_sizes.cljs │ ├── group_vertical.cljs │ ├── loading.cljs │ ├── sizes.cljs │ ├── split_basic.cljs │ ├── split_dropup.cljs │ ├── split_right.cljs │ ├── tag_types.cljs │ ├── toolbar_basic.cljs │ └── types.cljs │ ├── glyphicon.cljs │ ├── grid.cljs │ ├── input │ ├── addons.cljs │ ├── feedback.cljs │ ├── horizontal.cljs │ ├── types.cljs │ ├── validation.cljs │ └── wrapper.cljs │ ├── jumbotron │ └── basic.cljs │ ├── label │ ├── basic.cljs │ └── variations.cljs │ ├── modal │ ├── live.cljs │ └── static.cljs │ ├── nav │ ├── bar_basic.cljs │ ├── pills.cljs │ └── tabs.cljs │ ├── page_header.cljs │ ├── pagination │ ├── active.cljs │ ├── basic.cljs │ ├── centered.cljs │ ├── disabled.cljs │ └── navigation.cljs │ ├── panel │ ├── basic.cljs │ ├── collapsible.cljs │ ├── contextual.cljs │ ├── footer.cljs │ ├── group_accordion.cljs │ ├── group_controlled.cljs │ ├── group_uncontrolled.cljs │ ├── heading.cljs │ └── list-group.cljs │ ├── popover │ └── basic.cljs │ ├── progressbar │ ├── active.cljs │ ├── basic.cljs │ ├── contextual.cljs │ ├── label.cljs │ ├── sr_only_label.cljs │ ├── stacked.cljs │ └── striped.cljs │ ├── table │ ├── basic.cljs │ └── responsive.cljs │ ├── tooltip │ └── basic.cljs │ └── well │ ├── basic.cljs │ └── sizes.cljs ├── docs └── src │ ├── clj │ └── om_bootstrap │ │ ├── macros.clj │ │ └── server.clj │ └── cljs │ └── om_bootstrap │ ├── docs.cljs │ └── docs │ ├── components.cljs │ ├── example.cljs │ ├── footer.cljs │ ├── getting_started.cljs │ ├── home.cljs │ ├── nav.cljs │ └── shared.cljs ├── project.clj ├── src └── om_bootstrap │ ├── button.cljs │ ├── grid.cljs │ ├── input.cljs │ ├── mixins.cljs │ ├── modal.cljs │ ├── nav.cljs │ ├── pagination.cljs │ ├── panel.cljs │ ├── progress_bar.cljs │ ├── random.cljs │ ├── table.cljs │ ├── types.cljs │ └── util.cljs ├── system.properties └── test ├── om_bootstrap ├── input_test.cljs ├── types_test.cljs └── util_test.cljs └── vendor ├── console-polyfill.js ├── es5-sham.js └── es5-shim.js /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | target 3 | out 4 | lib 5 | dump.rdb 6 | pom.xml 7 | # use glob syntax. 8 | syntax: glob 9 | *.class 10 | *~ 11 | .DS_Store 12 | *.#* 13 | *#* 14 | *.classpath 15 | *.project 16 | *.settings 17 | *.dot 18 | .lein-failures 19 | .repl 20 | .lein-deps-sum 21 | .lein-repl-history 22 | .lein-plugins 23 | .clojurescript-output 24 | repl 25 | .repl-* 26 | .lein-env 27 | .nrepl* 28 | checkouts 29 | schema.png 30 | dev/public/assets/main.js 31 | dev/public/generated 32 | dev/public/assets/generated 33 | .idea 34 | *.iml 35 | *-init.clj 36 | *.log -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: clojure 2 | lein: lein2 3 | script: lein2 test 4 | branches: 5 | only: 6 | - develop 7 | - master 8 | jdk: 9 | - openjdk7 10 | deploy: 11 | provider: heroku 12 | api_key: 13 | secure: R0sXGyTf9IP5MGpHay47fpuL0DGvIn5VbOjSFq1Syucp6Yt5RhhjOi99x0C1BtIXvDJzqvLEW3MDAgvi111iHiHTSv0w3lrb2vnHB0LpgZ0IPGAGazPILaWiC5jKgTXc2EXz3ByLi9gqegFuxVkTKOtDYieHWyWQWtAM2qAC+gk= 14 | app: om-bootstrap 15 | on: 16 | repo: racehub/om-bootstrap 17 | branch: develop 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.6.1 (2/3/2016) 2 | - Added pull right for nav bar. 3 | 4 | ## 0.6.0 (2/2/2016) 5 | 6 | - Major Changes: 7 | - Upgrade Clojure to 1.8 8 | - Upgrade Clojurescript to 1.7.228 9 | - Replace Weasel/Piggieback with Figwheel 10 | - Several other minor dependency upgrades 11 | 12 | ## 0.5.3 (7/13/2015) 13 | 14 | - Change `map` to `doseq` in unbind-root-close-handlers to force effects (https://github.com/racehub/om-bootstrap/pull/76) 15 | 16 | ## 0.5.2 (7/12/2015) 17 | 18 | - Changed collapsible panels to initialize closed, not open. 19 | - Fixes to nav items. 20 | 21 | ## 0.5.1 (6/15/2015) 22 | 23 | - Added `input-group-btn` (https://github.com/racehub/om-bootstrap/pull/69) 24 | 25 | ## 0.5.0 (4/16/2015) 26 | 27 | - Upgrade to Schema 0.4.0 and om-tools 0.3.11 (https://github.com/racehub/om-bootstrap/pull/67) 28 | 29 | ## 0.4.3 30 | 31 | - Fix bad references to `pager` in the docs. Replaced with `pagination`. 32 | 33 | ## 0.4.1 (2/26/2015) 34 | 35 | - Fix schema error in dropdown (https://github.com/racehub/om-bootstrap/pull/62) 36 | - Fix schema validation with input components (https://github.com/racehub/om-bootstrap/pull/60) 37 | 38 | ## 0.4.0 39 | 40 | - Upgrade to Om 0.8.x and React 0.12.x (https://github.com/racehub/om-bootstrap/pull/40) 41 | - Move React into the preamble on the docs site 42 | - Remove explicit React script include on the docs site HTML 43 | - Change `validReactComponent` call in `util.cljs` to `validReactElement` 44 | 45 | ## 0.3.6 (2/5/2015) 46 | 47 | - Actually build modal component (https://github.com/racehub/om-bootstrap/pull/53) 48 | 49 | ## 0.3.5 (2/2/2015) 50 | 51 | - Modal component, thanks to @dignati! (https://github.com/racehub/om-bootstrap/pull/50) 52 | - Support for collapsible panels, thanks to @dignati (https://github.com/racehub/om-bootstrap/pull/45) 53 | 54 | ## 0.3.4 (1/27/2015) 55 | 56 | - Turned Om into a provided dependency (https://github.com/racehub/om-bootstrap/pull/44) 57 | - add Pagination, thanks to @dignati (https://github.com/racehub/om-bootstrap/pull/47) 58 | - Fixes a bug where navs were un-expanded by default (https://github.com/racehub/om-bootstrap/pull/48) 59 | 60 | ## 0.3.3 (1/13/2015) 61 | 62 | - Added collapse functionality for navbars (https://github.com/racehub/om-bootstrap/pull/41) 63 | 64 | ## 0.3.2 (12/9/2014) 65 | 66 | - Added `href` tags to all `Show Code` links. Without these they weren't expanding on mobile browsers (https://github.com/racehub/om-bootstrap/issues/34) 67 | - Fixed compatibility issue with om-0.8.0-beta3, and added tests. 68 | - Upgraded clojure to 1.7.0-alpha2 69 | - Upgraded core.async to 0.1.346.0-17112a-alpha 70 | - Upgraded om-tools to 0.3.6 71 | - Upgraded schema to 0.3.1 72 | - Upgraded weasel to 0.4.2 73 | 74 | ## 0.3.1 (10/15/2014) 75 | 76 | - Revert schema upgrade... fancy that :) 77 | 78 | ## 0.3.0 (9/25/2014) 79 | 80 | - Upgrade to Schema 0.3.0 81 | 82 | ## 0.2.9 (9/20/2014) 83 | 84 | - Relaxes a bunch of required keys in schemas back to optional: https://github.com/racehub/om-bootstrap/pull/23 85 | - Converts `om-bootstrap.button/menu-item` to an Om component, so that a wrapping `dropdown` component can access its `:on-select` attribute. The interface stays the same: https://github.com/racehub/om-bootstrap/pull/25 86 | 87 | ## 0.2.8 88 | 89 | - Add `:list-group` to panels, makes body optional: https://github.com/racehub/om-bootstrap/pull/22 (@brutasse) 90 | 91 | ## 0.2.7 92 | 93 | - Added a bunch of tests to the `types` and `util` namespaces. 94 | - Don't nuke merged :refs: https://github.com/racehub/om-bootstrap/pull/20 (@pyr) 95 | 96 | ## 0.2.6 97 | 98 | - Upgraded Clojurescript dependency on the doc site to get around this bug: http://dev.clojure.org/jira/browse/CLJS-839. Added a note. 99 | 100 | This hash code bug was causing `bs-class-set`'s internal lookup in `class-map` to fail in Safari 7.0.x once the JS JIT compiler kicked in. 101 | 102 | From https://github.com/racehub/om-bootstrap/pull/13: 103 | - `om-bootstrap.util/clone-with-props` can now "clone" proper om components by injecting extra attributes into the om cursor. 104 | - `:on-select` handlers on top level nav elements now get called if set, along with the current nav-item `:on-select` handlers 105 | 106 | ### New Components 107 | 108 | - `dropdown-mixin` (mixins.cljs) 109 | - `menu-item`, `dropdown-menu`, `dropdown` (button.cljs) 110 | - `split` (ie, SplitButton) (button.cljs) 111 | - `navbar` (ie, SplitButton) (button.cljs) 112 | 113 | ## 0.2.5 114 | 115 | - Removed in-progress fade listeners. 116 | - Added glyphicon 117 | - Lots more examples for the documentation site 118 | 119 | ## 0.2.0 120 | 121 | - Added many components. 122 | - Created documentation site 123 | - Upgraded to Om 0.7.x and React 0.11 124 | 125 | ## 0.1.0 126 | 127 | * Initial Release. 128 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions to Om-Bootstrap are very welcome. (Thanks to the [Schema](https://github.com/prismatic/schema) project for the template for these contributing guidelines.) 4 | 5 | Please file bug reports on [GitHub](https://github.com/racehub/om-bootstrap/issues). 6 | 7 | For questions, feature requests, or discussion, please post on the Clojure [mailing list](https://groups.google.com/forum/#!forum/clojure). 8 | 9 | Contributions are preferred as GitHub pull requests on topic branches. Please send pull requests to the `develop` branch. All new work is based off of `develop`; release are cut by merging `develop` into `master` and generating a release tag. 10 | 11 | If you want to discuss a potential change before coding it up, please post on the mailing list or create a [GitHub issue](https://github.com/racehub/om-bootstrap/issues). 12 | 13 | Om-Bootstrap is currently lacking heavy tests, but it does have a very solid example documentation site. Before submitting a pull request, we ask that you: 14 | 15 | * please try to follow the conventions in the existing code, including standard Emacs indentation, no trailing whitespace, and a max width of 95 columns 16 | * rebase your feature branch on the latest develop branch 17 | * ensure any new code is well-tested, and if possible, any issue fixed is covered by one or more new tests 18 | * check that all of the tests pass 19 | * If you're adding a new component, add an example to the documentation site using the instructions below. 20 | 21 | ## Running the Tests 22 | 23 | To run the ClojureScript tests, simply run `lein test` in the project root. Leiningen will build the relevant Clojurescript files and run all tests for you. You must have [PhantomJS](http://phantomjs.org/) installed for the tests to run. 24 | 25 | ## Running the Documentation Site 26 | 27 | To fire up the documentation site locally, all you need is `lein run`. The command will generate the development-mode CSS and start the webserver on port 8080 by default. (You can override this port by setting the `PORT` environment variable: 28 | 29 | ```sh 30 | $ export PORT=4040; lein run 31 | ``` 32 | 33 | This is the easiest way to see quick results if you're trying to add a new example to the doc site. If you want live feedback, run this in the background for CLJS autogeneration: 34 | 35 | ```clojure 36 | lein cljsbuild auto docs 37 | ``` 38 | 39 | You'll have to change and save `./docs/src/cljs/om_bootstrap/docs/components.cljs` to get new snippets to load, since `cljsbuild`'s watcher doesn't watch the `dev` folder. 40 | 41 | ## Writing a Documentation Example 42 | 43 | The ClojureScript documentation site lives under `docs/src/cljs/om_bootstrap/docs.cljs`. Each type of component has its own section, called `*-block` (`button-block`, for example). 44 | 45 | Each inlined example is generated from a `cljs` file located in the `dev/snippets` folder in the root of the project. Once a snippet is present, including `(->example (slurp-example ))` in a component will render the snippet in an "Example" box with the code accessible via a "show/hide code" toggle. 46 | 47 | One example is the "active" button code, located at `dev/snippets/button/active.cljs`: 48 | 49 | ```clojure 50 | #_ 51 | (:require [om-bootstrap.button :as b]) 52 | 53 | (b/toolbar {} 54 | (b/button {:bs-style "primary" :bs-size "large" :active? true} 55 | "Primary button") 56 | (b/button {:bs-size "large" :bs-style "default" :active? true} 57 | "Button")) 58 | ``` 59 | 60 | This is included in the documentation sit with the following call: 61 | 62 | ```clojure 63 | (->example (slurp-example "button/active")) 64 | ``` 65 | 66 | The `dev/snippets` prefix, and the `.cljs` are left off. 67 | 68 | Also, notice the `#_` reader macro before the import statement. That statement's not actually used! It's just there to provide guidance to the user. The `#_` gets stripped out when the code's displayed to the user under the "show/hide code" toggle. The rest of the snippet gets evaluated in the environment of `docs.cljs`, so you'll have to include new `require` aliases if you want to use other files in these snippets. 69 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 RaceHub. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: java $JVM_OPTS -jar target/om-bootstrap.jar -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Om-Bootstrap [![Build Status](https://secure.travis-ci.org/racehub/om-bootstrap.png)](http://travis-ci.org/racehub/om-bootstrap) 2 | 3 | A ClojureScript library of [Bootstrap 3](http://getbootstrap.com) components built on top of [Om](https://github.com/swannodette/om). See the [documentation site](http://om-bootstrap.herokuapp.com/) for a ton of usage examples. 4 | 5 | Here's the latest Leiningen version info: 6 | 7 | [![Clojars Project](http://clojars.org/racehub/om-bootstrap/latest-version.svg)](http://clojars.org/racehub/om-bootstrap) 8 | 9 | You'll also need to add Om: 10 | 11 | ```clojure 12 | [org.omcljs/om "0.8.8"] 13 | ``` 14 | 15 | You can find more detailed information on how to configure your Clojurescript project to use Om-Bootstrap on the documentation site's [Getting Started section](http://om-bootstrap.herokuapp.com/getting-started). 16 | 17 | **This is an alpha release. The API and organizational structure are 18 | subject to change. Comments and contributions are much appreciated.** 19 | 20 | ## Bootstrap Components 21 | 22 | This project's goal is to provide wrappers for all Bootstrap 3 components, active or inactive, so they can be used easily in [Om](https://github.com/swannodette/om) / ClojureScript projects. 23 | 24 | All component inputs and options are documented with Prismatic's [Schema](https://github.com/prismatic/schema) library. These schemas also allows for optional runtime validation of component inputs. See the [Schema README]([Schema](https://github.com/prismatic/schema)) for more details on this. 25 | 26 | Om-Bootstrap's [documentation site](http://om-bootstrap.herokuapp.com/) has usage examples for all components that exist so far. The following components are currently complete: 27 | 28 | * `button`, `button-group`, `toolbar` (button.cljs) 29 | * `dropdown-menu`, `menu-item`, `dropdown`, `split` (button.cljs) 30 | * `modal` (modal.cljs) 31 | * `input` (input.cljs) 32 | * `panel` (panel.cljs) 33 | * `jumbotron` (random.cljs) 34 | * `label` (random.cljs) 35 | * `well` (random.cljs) 36 | * `page-header` (random.cljs) 37 | * `grid`, `row`, `col` (grid.cljs) 38 | * `glyphicon` (random.cljs) 39 | * `tooltip` (random.cljs) 40 | * `alert` (random.cljs) 41 | * `nav`, `nav-item`, `navbar` (nav.cljs) 42 | * `popover` (random.cljs) 43 | * `badge` (random.cljs) 44 | * `table` (table.cljs) 45 | 46 | ## Mixins 47 | 48 | The project contains a few mixins that help in writing active Om components. The current set of mixins makes it easy to set listeners and timeouts on some component, and guarantee that they'll be cleaned up when the component unmounts: 49 | 50 | * `set-listener-mixin` (mixins.cljs) 51 | * `set-timeout-mixin` (mixins.cljs) 52 | * `dropdown-mixin` (mixins.cljs) 53 | 54 | ## Components In Progress 55 | 56 | * ModalTrigger (modal.cljs) 57 | * ProgressBar (progress_bar.cljs) 58 | 59 | ## Needed Components 60 | 61 | These, and the mixins below, are the project's biggest TODOs. 62 | 63 | * Subnav (?) 64 | * Panel (hard), PanelGroup (easy), Accordion (easy) 65 | * TabbedArea, TabPane 66 | * Carousel 67 | * CarouselItem 68 | 69 | ### Needed Mixins 70 | 71 | * FadeMixin 72 | * OverlayMixin 73 | 74 | ## ClojureScript Repl 75 | 76 | `om-bootstrap` comes with a development environment you can use to hack on the demo project. First, start the repl with: 77 | 78 | ```clojure 79 | lein repl 80 | ``` 81 | 82 | You'll be dropped into the `om-bootstrap.server` namespace. Fire up the webapp by running `(-main)`. You can access the dev site at `http://localhost:8080`. (Set the `PORT` environment variable to customize the launch port.) 83 | 84 | Next, to fire up a Clojurescript repl you can use `lein figwheel`. This will start a Websocket repl using [Figwheel](https://github.com/bhauman/lein-figwheel). When you reload `http://localhost:8080`, it should automatically connect to Figwheel and anything you type at the repl will start evaluating. 85 | 86 | I personally like to start the repl with `lein repl :headless` and do all of this from Emacs. Whatever floats your boat. 87 | 88 | ## Supported Versions 89 | 90 | Om-Bootstrap works with the following dependencies: 91 | 92 | - Clojure 1.6.x, 1.7.x 93 | - React.JS 0.12.x 94 | - Om 0.8.x 95 | - Schema 0.4.x 96 | - Bootstrap 3.1.x (probably works on 3.2, haven't tested it) 97 | 98 | and the latest version of ClojureScript. Please create a [GitHub issue](https://github.com/racehub/om-bootstrap/issues) if you run into problems with these versions or would like to see further versions supported. 99 | 100 | Note that we've seen trouble with Safari 7.0.x on CLJS versions <= 0.0.2261. See [this ticket](https://github.com/racehub/om-bootstrap/issues/10) for details. 101 | 102 | ## Authors 103 | 104 | - Sam Ritchie 105 | - Dave Petrovics 106 | 107 | And a whole host of wonderful [contributors](https://github.com/racehub/om-bootstrap/graphs/contributors). 108 | 109 | We'd love to add your name to this list! See `CONTRIBUTING.md` for information on how to help out. 110 | 111 | ## Community and Contributions 112 | 113 | This project may grow large enough for its own mailing list someday, but for now please feel free to join the Clojure [mailing list](https://groups.google.com/forum/#!forum/clojure) to ask questions or discuss how you're using Om-Bootstrap. 114 | 115 | For announcements of new releases, you can follow [@RaceHubHQ](http://twitter.com/RaceHubHQ) on Twitter. 116 | 117 | We welcome contributions in the form of bug reports and pull requests! Please see `CONTRIBUTING.md` in the repo root for guidelines. 118 | 119 | ## Running the Tests 120 | 121 | To run the ClojureScript tests, simply run `lein test` in the project root. Leiningen will build the relevant Clojurescript files and run all tests for you. You must have [PhantomJS](http://phantomjs.org/) installed for the tests to run. 122 | 123 | ## Running the Documentation Site 124 | 125 | To fire up the documentation site locally, all you need is `lein run`. The command will generate the development-mode CSS and start the webserver on port 8080 by default. (You can override this port by setting the `PORT` environment variable: 126 | 127 | ```sh 128 | $ export PORT=4040; lein run 129 | ``` 130 | 131 | This is the easiest way to see quick results if you're trying to add a new example to the doc site. If you want live feedback, run this in the background for CLJS autogeneration: 132 | 133 | ```clojure 134 | lein cljsbuild auto docs 135 | ``` 136 | 137 | You'll have to change and save `./docs/src/cljs/om_bootstrap/docs/components.cljs` to get new snippets to load, since `cljsbuild`'s watcher doesn't watch the `dev` folder. 138 | 139 | ## Deploying to Heroku 140 | 141 | If you fork this project and would like to deploy a version of the documentation site to Heroku to show off, all you need to do is click this button: 142 | 143 | [![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy) 144 | 145 | And boom! Heroku will guide you through the process of deploying a fresh copy of `http://om-bootstrap.herokuapp.com`. 146 | 147 | ## Acknowledgements 148 | 149 | HUGE thanks to the [react-bootstrap](https://github.com/react-bootstrap/react-bootstrap) project, which I used as a reference when creating all components and the documentation site. 150 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Om-Bootstrap Doc Site", 3 | "description": "Documentation site for Om-Bootstrap; Bootstrap components on Om.", 4 | "repository": "https://github.com/racehub/om-bootstrap", 5 | "keywords": ["om", "react", "bootstrap", "ui"] 6 | } 7 | -------------------------------------------------------------------------------- /dev/externs/highlight.js: -------------------------------------------------------------------------------- 1 | var hljs = {}; 2 | hljs.highlightBlock = function(elem) {}; 3 | -------------------------------------------------------------------------------- /dev/public/assets/carousel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racehub/om-bootstrap/18fb7f67c306d208bcb012a1b765ac1641d7a00b/dev/public/assets/carousel.png -------------------------------------------------------------------------------- /dev/public/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racehub/om-bootstrap/18fb7f67c306d208bcb012a1b765ac1641d7a00b/dev/public/assets/logo.png -------------------------------------------------------------------------------- /dev/public/assets/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | * React Bootstrap Documentation 3 | * Special styles for presenting react-bootstrap's documentation and code examples. 4 | * Based on the Bootstrap Documentation styles and overridden as necessary. 5 | */ 6 | 7 | body { 8 | background-color: #f9f9f9; 9 | } 10 | 11 | .bs-docs-nav { 12 | background-color: #222; 13 | } 14 | 15 | .bs-docs-nav .navbar-nav>li>a { 16 | color: #aaa; 17 | font-weight: normal; 18 | } 19 | 20 | .bs-docs-nav .navbar-nav>li>a:hover,.bs-docs-nav .navbar-nav>.active>a, .bs-docs-nav .navbar-nav>.active>a:hover { 21 | background: #333; 22 | color: #fafafa; 23 | } 24 | 25 | @media (min-width: 768px) { 26 | 27 | .bs-docs-nav .navbar-nav>li>a { 28 | border-bottom: 3px solid #222; 29 | } 30 | .bs-docs-nav .navbar-nav>li>a:hover,.bs-docs-nav .navbar-nav>.active>a, .bs-docs-nav .navbar-nav>.active>a:hover { 31 | border-bottom: 3px solid #cc7a6f; 32 | } 33 | } 34 | 35 | .navbar>.container .navbar-brand, .navbar>.container-fluid .navbar-brand { 36 | color: #00d8ff; 37 | } 38 | 39 | .bs-docs-masthead, .bs-docs-header { 40 | background: #2d2d2d; 41 | filter: none; 42 | color: #e9e9e9; 43 | } 44 | 45 | .bs-docs-header h1 { 46 | color: #e9e9e9; 47 | } 48 | 49 | .bs-docs-header p { 50 | color: #e9e9e9; 51 | } 52 | 53 | .bs-docs-sidebar .nav>li>a { 54 | color: #666; 55 | } 56 | 57 | .bs-docs-sidebar .nav>li>a:hover, .bs-docs-sidebar .nav>li>a:focus { 58 | color: #cc7a6f; 59 | border-left: 1px solid #cc7a6f; 60 | } 61 | 62 | .back-to-top:hover { 63 | color: #cc7a6f; 64 | } 65 | 66 | 67 | .CodeMirror { 68 | height: auto; 69 | } 70 | 71 | .bs-example .btn-toolbar + .btn-toolbar { 72 | margin-top: 10px; 73 | } 74 | 75 | .bs-example .modal { 76 | position: relative; 77 | top: auto; 78 | right: auto; 79 | left: auto; 80 | bottom: auto; 81 | z-index: 1; 82 | display: block; 83 | } 84 | 85 | .bs-docs-booticon { 86 | background: url('./logo.png') 0 0 no-repeat; 87 | background-size: contain; 88 | border: 0; 89 | width: 200px; 90 | height: 200px; 91 | } 92 | 93 | .bs-example-scroll { 94 | overflow: scroll; 95 | height: 200px; 96 | } 97 | 98 | .bs-example-scroll > div { 99 | position: relative; 100 | padding: 100px 0; 101 | } 102 | 103 | .playground { 104 | margin-bottom: 36px; 105 | } 106 | 107 | .bs-example { 108 | margin-bottom: 0; 109 | } 110 | 111 | .bs-example + .highlight { 112 | margin-top: 0; 113 | margin-bottom: 0; 114 | border-top: none; 115 | border-bottom-right-radius: 0; 116 | } 117 | 118 | .code-toggle { 119 | float: right; 120 | display: inline-block; 121 | position: relative; 122 | top: -1px; 123 | background: #fafafa; 124 | border-bottom-left-radius: 4px; 125 | border-bottom-right-radius: 4px; 126 | border: 1px solid #e1e1e8; 127 | border-top: none; 128 | padding: 4px 8px; 129 | } 130 | 131 | @media (min-width: 768px) { 132 | .code-toggle { 133 | background: #fff; 134 | } 135 | } 136 | 137 | .code-toggle.open { 138 | background: #f8f5ec; 139 | } 140 | -------------------------------------------------------------------------------- /dev/public/vendor/bootstrap/docs.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Docs (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under the Creative Commons Attribution 3.0 Unported License. For 5 | * details, see http://creativecommons.org/licenses/by/3.0/. 6 | */body{position:relative}.table code{font-size:13px;font-weight:400}.btn-outline{color:#563d7c;background-color:transparent;border-color:#563d7c}.btn-outline:hover,.btn-outline:focus,.btn-outline:active{color:#fff;background-color:#563d7c;border-color:#563d7c}.btn-outline-inverse{color:#fff;background-color:transparent;border-color:#cdbfe3}.btn-outline-inverse:hover,.btn-outline-inverse:focus,.btn-outline-inverse:active{color:#563d7c;text-shadow:none;background-color:#fff;border-color:#fff}.bs-docs-booticon{display:block;font-weight:500;color:#fff;text-align:center;cursor:default;background-color:#563d7c;border-radius:15%}.bs-docs-booticon-sm{width:30px;height:30px;font-size:20px;line-height:28px}.bs-docs-booticon-lg{width:144px;height:144px;font-size:108px;line-height:140px}.bs-docs-booticon-inverse{color:#563d7c;background-color:#fff}.bs-docs-booticon-outline{background-color:transparent;border:1px solid #cdbfe3}.bs-docs-nav{margin-bottom:0;background-color:#fff;border-bottom:0}.bs-home-nav .bs-nav-b{display:none}.bs-docs-nav .navbar-brand,.bs-docs-nav .navbar-nav>li>a{font-weight:500;color:#563d7c}.bs-docs-nav .navbar-nav>li>a:hover,.bs-docs-nav .navbar-nav>.active>a,.bs-docs-nav .navbar-nav>.active>a:hover{color:#463265;background-color:#f9f9f9}.bs-docs-nav .navbar-toggle .icon-bar{background-color:#563d7c}.bs-docs-nav .navbar-header .navbar-toggle{border-color:#fff}.bs-docs-nav .navbar-header .navbar-toggle:hover,.bs-docs-nav .navbar-header .navbar-toggle:focus{background-color:#f9f9f9;border-color:#f9f9f9}.bs-docs-footer{padding-top:40px;padding-bottom:40px;margin-top:100px;color:#777;text-align:center;border-top:1px solid #e5e5e5}.bs-docs-footer-links{padding-left:0;margin-top:20px;color:#999}.bs-docs-footer-links li{display:inline;padding:0 2px}.bs-docs-footer-links li:first-child{padding-left:0}@media (min-width:768px){.bs-docs-footer p{margin-bottom:0}}.bs-docs-social{margin-bottom:20px;text-align:center}.bs-docs-social-buttons{display:inline-block;padding-left:0;margin-bottom:0;list-style:none}.bs-docs-social-buttons li{display:inline-block;padding:5px 8px;line-height:1}.bs-docs-social-buttons .twitter-follow-button{width:225px!important}.bs-docs-social-buttons .twitter-share-button{width:98px!important}.github-btn{overflow:hidden;border:0}.bs-docs-masthead,.bs-docs-header{position:relative;padding:30px 15px;color:#cdbfe3;text-align:center;text-shadow:0 1px 0 rgba(0,0,0,.1);background-color:#6f5499;background-image:-webkit-gradient(linear,left top,left bottom,from(#563d7c),to(#6f5499));background-image:-webkit-linear-gradient(top,#563d7c 0,#6f5499 100%);background-image:-o-linear-gradient(top,#563d7c 0,#6f5499 100%);background-image:linear-gradient(to bottom,#563d7c 0,#6f5499 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#563d7c', endColorstr='#6F5499', GradientType=0);background-repeat:repeat-x}.bs-docs-masthead .bs-docs-booticon{margin:0 auto 30px}.bs-docs-masthead h1{font-weight:300;line-height:1;color:#fff}.bs-docs-masthead .lead{margin:0 auto 30px;font-size:20px;color:#fff}.bs-docs-masthead .version{margin-top:-15px;margin-bottom:30px;color:#9783b9}.bs-docs-masthead .btn{width:100%;padding:15px 30px;font-size:20px}@media (min-width:480px){.bs-docs-masthead .btn{width:auto}}@media (min-width:768px){.bs-docs-masthead{padding:80px 0}.bs-docs-masthead h1{font-size:60px}.bs-docs-masthead .lead{font-size:24px}}@media (min-width:992px){.bs-docs-masthead .lead{width:80%;font-size:30px}}.bs-docs-header{margin-bottom:40px;font-size:20px}.bs-docs-header h1{margin-top:0;color:#fff}.bs-docs-header p{margin-bottom:0;font-weight:300;line-height:1.4}.bs-docs-header .container{position:relative}@media (min-width:768px){.bs-docs-header{padding-top:60px;padding-bottom:60px;font-size:24px;text-align:left}.bs-docs-header h1{font-size:60px;line-height:1}}@media (min-width:992px){.bs-docs-header h1,.bs-docs-header p{margin-right:380px}}.carbonad{width:auto!important;height:auto!important;padding:20px!important;margin:30px -30px -31px!important;overflow:hidden;font-size:13px!important;line-height:16px!important;text-align:left;background:transparent!important;border:solid #866ab3!important;border-width:1px 0!important}.carbonad-img{margin:0!important}.carbonad-text,.carbonad-tag{display:block!important;float:none!important;width:auto!important;height:auto!important;margin-left:145px!important;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif!important}.carbonad-text{padding-top:0!important}.carbonad-tag{color:inherit!important;text-align:left!important}.carbonad-text a,.carbonad-tag a{color:#fff!important}.carbonad #azcarbon>img{display:none}@media (min-width:480px){.carbonad{width:330px!important;margin:20px auto!important;border-width:1px!important;border-radius:4px}.bs-docs-masthead .carbonad{margin:50px auto 0!important}}@media (min-width:768px){.carbonad{margin-right:0!important;margin-left:0!important}}@media (min-width:992px){.carbonad{position:absolute;top:0;right:15px;width:330px!important;padding:15px!important;margin:0!important}.bs-docs-masthead .carbonad{position:static}}.bs-docs-featurette{padding-top:40px;padding-bottom:40px;font-size:16px;line-height:1.5;color:#555;text-align:center;background-color:#fff;border-bottom:1px solid #e5e5e5}.bs-docs-featurette+.bs-docs-footer{margin-top:0;border-top:0}.bs-docs-featurette-title{margin-bottom:5px;font-size:30px;font-weight:400;color:#333}.half-rule{width:100px;margin:40px auto}.bs-docs-featurette h3{margin-bottom:5px;font-weight:400;color:#333}.bs-docs-featurette-img{display:block;margin-bottom:20px;color:#333}.bs-docs-featurette-img:hover{color:#428bca;text-decoration:none}.bs-docs-featurette-img img{display:block;margin-bottom:15px}@media (min-width:480px){.bs-docs-featurette .img-responsive{margin-top:30px}}@media (min-width:768px){.bs-docs-featurette{padding-top:100px;padding-bottom:100px}.bs-docs-featurette-title{font-size:40px}.bs-docs-featurette .lead{max-width:80%;margin-right:auto;margin-left:auto}.bs-docs-featurette .img-responsive{margin-top:0}}.bs-docs-featured-sites{margin-right:-1px;margin-left:-1px}.bs-docs-featured-sites .col-xs-6{padding:1px}.bs-docs-featured-sites .img-responsive{margin-top:0}@media (min-width:768px){.bs-docs-featured-sites .col-sm-3:first-child img{border-top-left-radius:4px;border-bottom-left-radius:4px}.bs-docs-featured-sites .col-sm-3:last-child img{border-top-right-radius:4px;border-bottom-right-radius:4px}}.bs-examples .thumbnail{margin-bottom:10px}.bs-examples h4{margin-bottom:5px}.bs-examples p{margin-bottom:20px}@media (max-width:480px){.bs-examples{margin-right:-10px;margin-left:-10px}.bs-examples>[class^=col-]{padding-right:10px;padding-left:10px}}.bs-docs-sidebar.affix{position:static}@media (min-width:768px){.bs-docs-sidebar{padding-left:20px}}.bs-docs-sidenav{margin-top:20px;margin-bottom:20px}.bs-docs-sidebar .nav>li>a{display:block;padding:4px 20px;font-size:13px;font-weight:500;color:#999}.bs-docs-sidebar .nav>li>a:hover,.bs-docs-sidebar .nav>li>a:focus{padding-left:19px;color:#563d7c;text-decoration:none;background-color:transparent;border-left:1px solid #563d7c}.bs-docs-sidebar .nav>.active>a,.bs-docs-sidebar .nav>.active:hover>a,.bs-docs-sidebar .nav>.active:focus>a{padding-left:18px;font-weight:700;color:#563d7c;background-color:transparent;border-left:2px solid #563d7c}.bs-docs-sidebar .nav .nav{display:none;padding-bottom:10px}.bs-docs-sidebar .nav .nav>li>a{padding-top:1px;padding-bottom:1px;padding-left:30px;font-size:12px;font-weight:400}.bs-docs-sidebar .nav .nav>li>a:hover,.bs-docs-sidebar .nav .nav>li>a:focus{padding-left:29px}.bs-docs-sidebar .nav .nav>.active>a,.bs-docs-sidebar .nav .nav>.active:hover>a,.bs-docs-sidebar .nav .nav>.active:focus>a{padding-left:28px;font-weight:500}.back-to-top,.bs-docs-theme-toggle{display:none;padding:4px 10px;margin-top:10px;margin-left:10px;font-size:12px;font-weight:500;color:#999}.back-to-top:hover,.bs-docs-theme-toggle:hover{color:#563d7c;text-decoration:none}.bs-docs-theme-toggle{margin-top:0}@media (min-width:768px){.back-to-top,.bs-docs-theme-toggle{display:block}}@media (min-width:992px){.bs-docs-sidebar .nav>.active>ul{display:block}.bs-docs-sidebar.affix,.bs-docs-sidebar.affix-bottom{width:213px}.bs-docs-sidebar.affix{position:fixed;top:20px}.bs-docs-sidebar.affix-bottom{position:absolute}.bs-docs-sidebar.affix-bottom .bs-docs-sidenav,.bs-docs-sidebar.affix .bs-docs-sidenav{margin-top:0;margin-bottom:0}}@media (min-width:1200px){.bs-docs-sidebar.affix-bottom,.bs-docs-sidebar.affix{width:263px}}.bs-docs-section{margin-bottom:60px}.bs-docs-section:last-child{margin-bottom:0}h1[id]{padding-top:20px;margin-top:0}.bs-callout{padding:20px;margin:20px 0;border:1px solid #eee;border-left-width:5px;border-radius:3px}.bs-callout h4{margin-top:0;margin-bottom:5px}.bs-callout p:last-child{margin-bottom:0}.bs-callout code{border-radius:3px}.bs-callout+.bs-callout{margin-top:-5px}.bs-callout-danger{border-left-color:#d9534f}.bs-callout-danger h4{color:#d9534f}.bs-callout-warning{border-left-color:#f0ad4e}.bs-callout-warning h4{color:#f0ad4e}.bs-callout-info{border-left-color:#5bc0de}.bs-callout-info h4{color:#5bc0de}.color-swatches{margin:0 -5px;overflow:hidden}.color-swatch{float:left;width:60px;height:60px;margin:0 5px;border-radius:3px}@media (min-width:768px){.color-swatch{width:100px;height:100px}}.color-swatches .gray-darker{background-color:#222}.color-swatches .gray-dark{background-color:#333}.color-swatches .gray{background-color:#555}.color-swatches .gray-light{background-color:#999}.color-swatches .gray-lighter{background-color:#eee}.color-swatches .brand-primary{background-color:#428bca}.color-swatches .brand-success{background-color:#5cb85c}.color-swatches .brand-warning{background-color:#f0ad4e}.color-swatches .brand-danger{background-color:#d9534f}.color-swatches .brand-info{background-color:#5bc0de}.color-swatches .bs-purple{background-color:#563d7c}.color-swatches .bs-purple-light{background-color:#c7bfd3}.color-swatches .bs-purple-lighter{background-color:#e5e1ea}.color-swatches .bs-gray{background-color:#f9f9f9}.bs-team .team-member{line-height:32px;color:#555}.bs-team .team-member:hover{color:#333;text-decoration:none}.bs-team .github-btn{float:right;width:180px;height:20px;margin-top:6px}.bs-team img{float:left;width:32px;margin-right:10px;border-radius:4px}.show-grid{margin-bottom:15px}.show-grid [class^=col-]{padding-top:10px;padding-bottom:10px;background-color:#eee;background-color:rgba(86,61,124,.15);border:1px solid #ddd;border:1px solid rgba(86,61,124,.2)}.bs-example{position:relative;padding:45px 15px 15px;margin:0 -15px 15px;border-color:#e5e5e5 #eee #eee;border-style:solid;border-width:1px 0;-webkit-box-shadow:inset 0 3px 6px rgba(0,0,0,.05);box-shadow:inset 0 3px 6px rgba(0,0,0,.05)}.bs-example:after{position:absolute;top:15px;left:15px;font-size:12px;font-weight:700;color:#959595;text-transform:uppercase;letter-spacing:1px;content:"Example"}.bs-example+.highlight{margin:-15px -15px 15px;border-width:0 0 1px;border-radius:0}@media (min-width:768px){.bs-example{margin-right:0;margin-left:0;background-color:#fff;border-color:#ddd;border-width:1px;border-radius:4px 4px 0 0;-webkit-box-shadow:none;box-shadow:none}.bs-example+.highlight{margin-top:-16px;margin-right:0;margin-left:0;border-width:1px;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.bs-example-standalone{border-radius:4px}}.bs-example .container{width:auto}.bs-example>p:last-child,.bs-example>ul:last-child,.bs-example>ol:last-child,.bs-example>blockquote:last-child,.bs-example>.form-control:last-child,.bs-example>.table:last-child,.bs-example>.navbar:last-child,.bs-example>.jumbotron:last-child,.bs-example>.alert:last-child,.bs-example>.panel:last-child,.bs-example>.list-group:last-child,.bs-example>.well:last-child,.bs-example>.progress:last-child,.bs-example>.table-responsive:last-child>.table{margin-bottom:0}.bs-example>p>.close{float:none}.bs-example-type .table .type-info{color:#999;vertical-align:middle}.bs-example-type .table td{padding:15px 0;border-color:#eee}.bs-example-type .table tr:first-child td{border-top:0}.bs-example-type h1,.bs-example-type h2,.bs-example-type h3,.bs-example-type h4,.bs-example-type h5,.bs-example-type h6{margin:0}.bs-example-bg-classes p{padding:15px}.bs-example>.img-circle,.bs-example>.img-rounded,.bs-example>.img-thumbnail{margin:5px}.bs-example>.table-responsive>.table{background-color:#fff}.bs-example>.btn,.bs-example>.btn-group{margin-top:5px;margin-bottom:5px}.bs-example>.btn-toolbar+.btn-toolbar{margin-top:10px}.bs-example-control-sizing select,.bs-example-control-sizing input[type=text]+input[type=text]{margin-top:10px}.bs-example-form .input-group{margin-bottom:10px}.bs-example>textarea.form-control{resize:vertical}.bs-example>.list-group{max-width:400px}.bs-example .navbar:last-child{margin-bottom:0}.bs-navbar-top-example,.bs-navbar-bottom-example{z-index:1;padding:0;overflow:hidden}.bs-navbar-top-example .navbar-header,.bs-navbar-bottom-example .navbar-header{margin-left:0}.bs-navbar-top-example .navbar-fixed-top,.bs-navbar-bottom-example .navbar-fixed-bottom{position:relative;margin-right:0;margin-left:0}.bs-navbar-top-example{padding-bottom:45px}.bs-navbar-top-example:after{top:auto;bottom:15px}.bs-navbar-top-example .navbar-fixed-top{top:-1px}.bs-navbar-bottom-example{padding-top:45px}.bs-navbar-bottom-example .navbar-fixed-bottom{bottom:-1px}.bs-navbar-bottom-example .navbar{margin-bottom:0}@media (min-width:768px){.bs-navbar-top-example .navbar-fixed-top,.bs-navbar-bottom-example .navbar-fixed-bottom{position:absolute}}.bs-example .pagination{margin-top:10px;margin-bottom:10px}.bs-example>.pager{margin-top:0}.bs-example-modal{background-color:#f5f5f5}.bs-example-modal .modal{position:relative;top:auto;right:auto;bottom:auto;left:auto;z-index:1;display:block}.bs-example-modal .modal-dialog{left:auto;margin-right:auto;margin-left:auto}.bs-example>.dropdown>.dropdown-toggle{float:left}.bs-example>.dropdown>.dropdown-menu{position:static;display:block;margin-bottom:5px;clear:left}.bs-example-tabs .nav-tabs{margin-bottom:15px}.bs-example-tooltips{text-align:center}.bs-example-tooltips>.btn{margin-top:5px;margin-bottom:5px}.bs-example-popover{padding-bottom:24px;background-color:#f9f9f9}.bs-example-popover .popover{position:relative;display:block;float:left;width:260px;margin:20px}.scrollspy-example{position:relative;height:200px;margin-top:10px;overflow:auto}.highlight{padding:9px 14px;margin-bottom:14px;background-color:#f7f7f9;border:1px solid #e1e1e8;border-radius:4px}.highlight pre{padding:0;margin-top:0;margin-bottom:0;word-break:normal;word-wrap:nowrap;white-space:nowrap;background-color:transparent;border:0}.highlight pre code{font-size:inherit;color:#333}.highlight pre code:first-child{display:inline-block;padding-right:45px}.table-responsive .highlight pre{white-space:normal}.bs-table th small,.responsive-utilities th small{display:block;font-weight:400;color:#999}.responsive-utilities tbody th{font-weight:400}.responsive-utilities td{text-align:center}.responsive-utilities td.is-visible{color:#468847;background-color:#dff0d8!important}.responsive-utilities td.is-hidden{color:#ccc;background-color:#f9f9f9!important}.responsive-utilities-test{margin-top:5px}.responsive-utilities-test .col-xs-6{margin-bottom:10px}.responsive-utilities-test span{display:block;padding:15px 10px;font-size:14px;font-weight:700;line-height:1.1;text-align:center;border-radius:4px}.visible-on .col-xs-6 .hidden-xs,.visible-on .col-xs-6 .hidden-sm,.visible-on .col-xs-6 .hidden-md,.visible-on .col-xs-6 .hidden-lg,.hidden-on .col-xs-6 .hidden-xs,.hidden-on .col-xs-6 .hidden-sm,.hidden-on .col-xs-6 .hidden-md,.hidden-on .col-xs-6 .hidden-lg{color:#999;border:1px solid #ddd}.visible-on .col-xs-6 .visible-xs-block,.visible-on .col-xs-6 .visible-sm-block,.visible-on .col-xs-6 .visible-md-block,.visible-on .col-xs-6 .visible-lg-block,.hidden-on .col-xs-6 .visible-xs-block,.hidden-on .col-xs-6 .visible-sm-block,.hidden-on .col-xs-6 .visible-md-block,.hidden-on .col-xs-6 .visible-lg-block{color:#468847;background-color:#dff0d8;border:1px solid #d6e9c6}.bs-glyphicons{margin:0 -10px 20px;overflow:hidden}.bs-glyphicons-list{padding-left:0;list-style:none}.bs-glyphicons li{float:left;width:25%;height:115px;padding:10px;font-size:10px;line-height:1.4;text-align:center;background-color:#f9f9f9;border:1px solid #fff}.bs-glyphicons .glyphicon{margin-top:5px;margin-bottom:10px;font-size:24px}.bs-glyphicons .glyphicon-class{display:block;text-align:center;word-wrap:break-word}.bs-glyphicons li:hover{color:#fff;background-color:#563d7c}@media (min-width:768px){.bs-glyphicons{margin-right:0;margin-left:0}.bs-glyphicons li{width:12.5%;font-size:12px}}.bs-customizer .toggle{float:right;margin-top:25px}.bs-customizer label{margin-top:10px;font-weight:500;color:#555}.bs-customizer h2{padding-top:30px;margin-top:0;margin-bottom:5px}.bs-customizer h3{margin-bottom:0}.bs-customizer h4{margin-top:15px;margin-bottom:0}.bs-customizer .bs-callout h4{margin-top:0;margin-bottom:5px}.bs-customizer input[type=text]{font-family:Menlo,Monaco,Consolas,"Courier New",monospace;background-color:#fafafa}.bs-customizer .help-block{margin-bottom:5px;font-size:12px}#less-section label{font-weight:400}.bs-customizer-input{float:left;width:33.333333%;padding-right:15px;padding-left:15px}.bs-customize-download .btn-outline{padding:20px}.bs-customizer-alert{position:fixed;top:0;right:0;left:0;z-index:1030;padding:15px 0;color:#fff;background-color:#d9534f;border-bottom:1px solid #b94441;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25);box-shadow:inset 0 1px 0 rgba(255,255,255,.25)}.bs-customizer-alert .close{margin-top:-4px;font-size:24px}.bs-customizer-alert p{margin-bottom:0}.bs-customizer-alert .glyphicon{margin-right:5px}.bs-customizer-alert pre{margin:10px 0 0;color:#fff;background-color:#a83c3a;border-color:#973634;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 2px 4px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)}.bs-dropzone{position:relative;padding:20px;margin-bottom:20px;color:#777;text-align:center;border:2px dashed #eee;border-radius:4px}.bs-dropzone h2{margin-top:0;margin-bottom:5px}.bs-dropzone .lead{margin-bottom:10px;font-weight:400;color:#333}.bs-dropzone hr{width:100px}.bs-dropzone p:last-child{margin-bottom:0}.bs-brand-logos{display:table;width:100%;margin-bottom:15px;overflow:hidden;color:#563d7c;background-color:#f9f9f9;border-radius:4px}.bs-brand-item{padding:60px 0;text-align:center}.bs-brand-item+.bs-brand-item{border-top:1px solid #fff}.bs-brand-logos .inverse{color:#fff;background-color:#563d7c}.bs-brand-item .svg{width:144px;height:144px}.bs-brand-item h1,.bs-brand-item h3{margin-top:0;margin-bottom:0}.bs-brand-item .bs-docs-booticon{margin-right:auto;margin-left:auto}.bs-brand-item .glyphicon{width:30px;height:30px;margin:10px auto -10px;line-height:30px;color:#fff;border-radius:50%}.bs-brand-item .glyphicon-ok{background-color:#5cb85c}.bs-brand-item .glyphicon-remove{background-color:#d9534f}@media (min-width:768px){.bs-brand-item{display:table-cell;width:1%}.bs-brand-item+.bs-brand-item{border-top:0;border-left:1px solid #fff}.bs-brand-item h1{font-size:60px}}.zero-clipboard{position:relative;display:none}.btn-clipboard{position:absolute;top:0;right:0;z-index:10;display:block;padding:5px 8px;font-size:12px;color:#777;cursor:pointer;background-color:#fff;border:1px solid #e1e1e8;border-radius:0 4px 0 4px}.btn-clipboard-hover{color:#fff;background-color:#563d7c;border-color:#563d7c}@media (min-width:768px){.zero-clipboard{display:block}}#focusedInput{border-color:#ccc;border-color:rgba(82,168,236,.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:0 0 8px rgba(82,168,236,.6);box-shadow:0 0 8px rgba(82,168,236,.6)}.hll{background-color:#ffc}.c{color:#999}.err{color:#A00;background-color:#FAA}.k{color:#069}.o{color:#555}.cm{color:#999}.cp{color:#099}.c1{color:#999}.cs{color:#999}.gd{background-color:#FCC;border:1px solid #C00}.ge{font-style:italic}.gr{color:red}.gh{color:#030}.gi{background-color:#CFC;border:1px solid #0C0}.go{color:#AAA}.gp{color:#009}.gu{color:#030}.gt{color:#9C6}.kc{color:#069}.kd{color:#069}.kn{color:#069}.kp{color:#069}.kr{color:#069}.kt{color:#078}.m{color:#F60}.s{color:#d44950}.na{color:#4f9fcf}.nb{color:#366}.nc{color:#0A8}.no{color:#360}.nd{color:#99F}.ni{color:#999}.ne{color:#C00}.nf{color:#C0F}.nl{color:#99F}.nn{color:#0CF}.nt{color:#2f6f9f}.nv{color:#033}.ow{color:#000}.w{color:#bbb}.mf{color:#F60}.mh{color:#F60}.mi{color:#F60}.mo{color:#F60}.sb{color:#C30}.sc{color:#C30}.sd{color:#C30;font-style:italic}.s2{color:#C30}.se{color:#C30}.sh{color:#C30}.si{color:#A00}.sx{color:#C30}.sr{color:#3AA}.s1{color:#C30}.ss{color:#FC3}.bp{color:#366}.vc{color:#033}.vg{color:#033}.vi{color:#033}.il{color:#F60}.css .o,.css .o+.nt,.css .nt+.nt{color:#999} -------------------------------------------------------------------------------- /dev/public/vendor/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racehub/om-bootstrap/18fb7f67c306d208bcb012a1b765ac1641d7a00b/dev/public/vendor/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /dev/public/vendor/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racehub/om-bootstrap/18fb7f67c306d208bcb012a1b765ac1641d7a00b/dev/public/vendor/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /dev/public/vendor/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racehub/om-bootstrap/18fb7f67c306d208bcb012a1b765ac1641d7a00b/dev/public/vendor/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /dev/public/vendor/highlight/highlight.pack.js: -------------------------------------------------------------------------------- 1 | var hljs=new function(){function j(v){return v.replace(/&/gm,"&").replace(//gm,">")}function t(v){return v.nodeName.toLowerCase()}function h(w,x){var v=w&&w.exec(x);return v&&v.index==0}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^lang(uage)?-/,"")});return v.filter(function(x){return i(x)||x=="no-highlight"})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(t(A)=="br"){z+=1}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset"}function E(G){F+=""}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=j(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+j(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};var E=function(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})};if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b="\\b("+D.bK.split(" ").join("|")+")\\b"}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?("+F.b+")\\.?":F.b}).concat([D.tE,D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}};D.continuation={}}x(y)}function c(S,L,J,R){function v(U,V){for(var T=0;T";U+=Z+'">';return U+X+Y}function N(){if(!I.k){return j(C)}var T="";var W=0;I.lR.lastIndex=0;var U=I.lR.exec(C);while(U){T+=j(C.substr(W,U.index-W));var V=E(I,U);if(V){H+=V[1];T+=w(V[0],j(U[0]))}else{T+=j(U[0])}W=I.lR.lastIndex;U=I.lR.exec(C)}return T+j(C.substr(W))}function F(){if(I.sL&&!f[I.sL]){return j(C)}var T=I.sL?c(I.sL,C,true,I.continuation.top):e(C);if(I.r>0){H+=T.r}if(I.subLanguageMode=="continuous"){I.continuation.top=T.top}return w(T.language,T.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(V,U){var T=V.cN?w(V.cN,"",true):"";if(V.rB){D+=T;C=""}else{if(V.eB){D+=j(U)+T;C=""}else{D+=T;C=U}}I=Object.create(V,{parent:{value:I}})}function G(T,X){C+=T;if(X===undefined){D+=Q();return 0}var V=v(X,I);if(V){D+=Q();P(V,X);return V.rB?0:X.length}var W=z(I,X);if(W){var U=I;if(!(U.rE||U.eE)){C+=X}D+=Q();do{if(I.cN){D+=""}H+=I.r;I=I.parent}while(I!=W.parent);if(U.eE){D+=j(X)}C="";if(W.starts){P(W.starts,"")}return U.rE?0:X.length}if(A(X,I)){throw new Error('Illegal lexeme "'+X+'" for mode "'+(I.cN||"")+'"')}C+=X;return X.length||1}var M=i(S);if(!M){throw new Error('Unknown language: "'+S+'"')}m(M);var I=R||M;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D+=w(K.cN,D,true)}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+=""}}return{r:H,value:D,language:S,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:j(L)}}else{throw O}}}function e(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:j(y)};var w=v;x.forEach(function(z){if(!i(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function g(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"
")}return v}function p(z){var y=b.useBR?z.innerHTML.replace(/\n/g,"").replace(/
|
]*>/g,"\n").replace(/<[^>]*>/g,""):z.textContent;var A=r(z);if(A=="no-highlight"){return}var v=A?c(A,y,true):e(y);var w=u(z);if(w.length){var x=document.createElementNS("http://www.w3.org/1999/xhtml","pre");x.innerHTML=v.value;v.value=q(w,u(x),y)}v.value=g(v.value);z.innerHTML=v.value;z.className+=" hljs "+(!A&&v.language||"");z.result={language:v.language,re:v.r};if(v.second_best){z.second_best={language:v.second_best.language,re:v.second_best.r}}}var b={classPrefix:"hljs-",tabReplace:null,useBR:false,languages:undefined};function s(v){b=o(b,v)}function l(){if(l.called){return}l.called=true;var v=document.querySelectorAll("pre code");Array.prototype.forEach.call(v,p)}function a(){addEventListener("DOMContentLoaded",l,false);addEventListener("load",l,false)}var f={};var n={};function d(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(function(y){n[y]=v})}}function k(){return Object.keys(f)}function i(v){return f[v]||f[n[v]]}this.highlight=c;this.highlightAuto=e;this.fixMarkup=g;this.highlightBlock=p;this.configure=s;this.initHighlighting=l;this.initHighlightingOnLoad=a;this.registerLanguage=d;this.listLanguages=k;this.getLanguage=i;this.inherit=o;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE]};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE]};this.PWM={b:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/};this.CLCM={cN:"comment",b:"//",e:"$",c:[this.PWM]};this.CBCM={cN:"comment",b:"/\\*",e:"\\*/",c:[this.PWM]};this.HCM={cN:"comment",b:"#",e:"$",c:[this.PWM]};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.CSSNM={cN:"number",b:this.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0};this.RM={cN:"regexp",b:/\//,e:/\/[gim]*/,i:/\n/,c:[this.BE,{b:/\[/,e:/\]/,r:0,c:[this.BE]}]};this.TM={cN:"title",b:this.IR,r:0};this.UTM={cN:"title",b:this.UIR,r:0}}();hljs.registerLanguage("clojure",function(l){var e={built_in:"def cond apply if-not if-let if not not= = < < > <= <= >= == + / * - rem quot neg? pos? delay? symbol? keyword? true? false? integer? empty? coll? list? set? ifn? fn? associative? sequential? sorted? counted? reversible? number? decimal? class? distinct? isa? float? rational? reduced? ratio? odd? even? char? seq? vector? string? map? nil? contains? zero? instance? not-every? not-any? libspec? -> ->> .. . inc compare do dotimes mapcat take remove take-while drop letfn drop-last take-last drop-while while intern condp case reduced cycle split-at split-with repeat replicate iterate range merge zipmap declare line-seq sort comparator sort-by dorun doall nthnext nthrest partition eval doseq await await-for let agent atom send send-off release-pending-sends add-watch mapv filterv remove-watch agent-error restart-agent set-error-handler error-handler set-error-mode! error-mode shutdown-agents quote var fn loop recur throw try monitor-enter monitor-exit defmacro defn defn- macroexpand macroexpand-1 for dosync and or when when-not when-let comp juxt partial sequence memoize constantly complement identity assert peek pop doto proxy defstruct first rest cons defprotocol cast coll deftype defrecord last butlast sigs reify second ffirst fnext nfirst nnext defmulti defmethod meta with-meta ns in-ns create-ns import refer keys select-keys vals key val rseq name namespace promise into transient persistent! conj! assoc! dissoc! pop! disj! use class type num float double short byte boolean bigint biginteger bigdec print-method print-dup throw-if printf format load compile get-in update-in pr pr-on newline flush read slurp read-line subvec with-open memfn time re-find re-groups rand-int rand mod locking assert-valid-fdecl alias resolve ref deref refset swap! reset! set-validator! compare-and-set! alter-meta! reset-meta! commute get-validator alter ref-set ref-history-count ref-min-history ref-max-history ensure sync io! new next conj set! to-array future future-call into-array aset gen-class reduce map filter find empty hash-map hash-set sorted-map sorted-map-by sorted-set sorted-set-by vec vector seq flatten reverse assoc dissoc list disj get union difference intersection extend extend-type extend-protocol int nth delay count concat chunk chunk-buffer chunk-append chunk-first chunk-rest max min dec unchecked-inc-int unchecked-inc unchecked-dec-inc unchecked-dec unchecked-negate unchecked-add-int unchecked-add unchecked-subtract-int unchecked-subtract chunk-next chunk-cons chunked-seq? prn vary-meta lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize"};var f="[a-zA-Z_0-9\\!\\.\\?\\-\\+\\*\\/\\<\\=\\>\\&\\#\\$';]+";var a="[\\s:\\(\\{]+\\d+(\\.\\d+)?";var d={cN:"number",b:a,r:0};var j=l.inherit(l.QSM,{i:null});var o={cN:"comment",b:";",e:"$",r:0};var n={cN:"collection",b:"[\\[\\{]",e:"[\\]\\}]"};var c={cN:"comment",b:"\\^"+f};var b={cN:"comment",b:"\\^\\{",e:"\\}"};var h={cN:"attribute",b:"[:]"+f};var m={cN:"list",b:"\\(",e:"\\)"};var g={eW:true,k:{literal:"true false nil"},r:0};var i={k:e,l:f,cN:"title",b:f,starts:g};m.c=[{cN:"comment",b:"comment"},i,g];g.c=[m,j,c,b,o,h,n,d];n.c=[m,j,c,o,h,n,d];return{aliases:["clj"],i:/\S/,c:[o,m,{cN:"prompt",b:/^=> /,starts:{e:/\n\n|\Z/}}]}}); -------------------------------------------------------------------------------- /dev/public/vendor/highlight/solarized.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; 9 | overflow-x: auto; 10 | padding: 0.5em; 11 | background: #fdf6e3; 12 | color: #657b83; 13 | } 14 | 15 | .hljs-comment, 16 | .hljs-template_comment, 17 | .diff .hljs-header, 18 | .hljs-doctype, 19 | .hljs-pi, 20 | .lisp .hljs-string, 21 | .hljs-javadoc { 22 | color: #93a1a1; 23 | } 24 | 25 | /* Solarized Green */ 26 | .hljs-keyword, 27 | .hljs-winutils, 28 | .method, 29 | .hljs-addition, 30 | .css .hljs-tag, 31 | .hljs-request, 32 | .hljs-status, 33 | .nginx .hljs-title { 34 | color: #859900; 35 | } 36 | 37 | /* Solarized Cyan */ 38 | .hljs-number, 39 | .hljs-command, 40 | .hljs-string, 41 | .hljs-tag .hljs-value, 42 | .hljs-rules .hljs-value, 43 | .hljs-phpdoc, 44 | .tex .hljs-formula, 45 | .hljs-regexp, 46 | .hljs-hexcolor, 47 | .hljs-link_url { 48 | color: #2aa198; 49 | } 50 | 51 | /* Solarized Blue */ 52 | .hljs-title, 53 | .hljs-localvars, 54 | .hljs-chunk, 55 | .hljs-decorator, 56 | .hljs-built_in, 57 | .hljs-identifier, 58 | .vhdl .hljs-literal, 59 | .hljs-id, 60 | .css .hljs-function { 61 | color: #268bd2; 62 | } 63 | 64 | /* Solarized Yellow */ 65 | .hljs-attribute, 66 | .hljs-variable, 67 | .lisp .hljs-body, 68 | .smalltalk .hljs-number, 69 | .hljs-constant, 70 | .hljs-class .hljs-title, 71 | .hljs-parent, 72 | .haskell .hljs-type, 73 | .hljs-link_reference { 74 | color: #b58900; 75 | } 76 | 77 | /* Solarized Orange */ 78 | .hljs-preprocessor, 79 | .hljs-preprocessor .hljs-keyword, 80 | .hljs-pragma, 81 | .hljs-shebang, 82 | .hljs-symbol, 83 | .hljs-symbol .hljs-string, 84 | .diff .hljs-change, 85 | .hljs-special, 86 | .hljs-attr_selector, 87 | .hljs-subst, 88 | .hljs-cdata, 89 | .clojure .hljs-title, 90 | .css .hljs-pseudo, 91 | .hljs-header { 92 | color: #cb4b16; 93 | } 94 | 95 | /* Solarized Red */ 96 | .hljs-deletion, 97 | .hljs-important { 98 | color: #dc322f; 99 | } 100 | 101 | /* Solarized Violet */ 102 | .hljs-link_label { 103 | color: #6c71c4; 104 | } 105 | 106 | .tex .hljs-formula { 107 | background: #f8f5ec; 108 | } 109 | 110 | .solarized-light-wrapper { 111 | background-color: #f8f5ec; 112 | color: #637c84; 113 | } -------------------------------------------------------------------------------- /dev/snippets/alert/basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.random :as r] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (r/alert {:bs-style "warning"} 6 | (d/strong "Holy guacamole!") 7 | " Best check yo self, you're not looking too good.") 8 | -------------------------------------------------------------------------------- /dev/snippets/badge.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.random :as r] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (d/p "Badges " (r/badge {} 42)) 6 | -------------------------------------------------------------------------------- /dev/snippets/button/active.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b]) 3 | 4 | (b/toolbar {} 5 | (b/button {:bs-style "primary" :bs-size "large" :active? true} 6 | "Primary button") 7 | (b/button {:bs-size "large" :bs-style "default" :active? true} 8 | "Button")) 9 | -------------------------------------------------------------------------------- /dev/snippets/button/block.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b] 3 | [om-tools.dom :include-macros true]) 4 | 5 | (d/div {:class "well" 6 | :style {:max-width 400 7 | :margin "0 auto 10px"}} 8 | (b/button {:bs-style "primary" :bs-size "large" :block? true} 9 | "Block level button") 10 | (b/button {:bs-size "large" :block? true} 11 | "Block level button")) 12 | -------------------------------------------------------------------------------- /dev/snippets/button/disabled.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b]) 3 | 4 | (b/toolbar {} 5 | (b/button {:bs-style "primary" :bs-size "large" :disabled? true} 6 | "Primary button") 7 | (b/button {:bs-size "large" :bs-style "default" :disabled? true} 8 | "Button")) 9 | -------------------------------------------------------------------------------- /dev/snippets/button/dropdown_basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b]) 3 | 4 | (b/toolbar 5 | {} 6 | (for [title ["Default" "Primary" "Success" "Info" "Warning" "Danger" "Link"] 7 | :let [style (.toLowerCase title)]] 8 | (b/dropdown {:bs-style style, :title title} 9 | (b/menu-item {:key 1} "Action") 10 | (b/menu-item {:key 2} "Another action") 11 | (b/menu-item {:key 3} "Something else here") 12 | (b/menu-item {:divider? true}) 13 | (b/menu-item {:key 4} "Separated link")))) 14 | -------------------------------------------------------------------------------- /dev/snippets/button/dropdown_sizes.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (d/div 6 | (for [[size title] [["large" "Large button"] 7 | ["small" "Small button"] 8 | ["xsmall" "Extra small button"]] 9 | :let [style (.toLowerCase title)]] 10 | (b/toolbar 11 | {} 12 | (b/dropdown {:bs-size size, :title title} 13 | (b/menu-item {:key 1} "Action") 14 | (b/menu-item {:key 2} "Another action") 15 | (b/menu-item {:key 3} "Something else here") 16 | (b/menu-item {:divider? true}) 17 | (b/menu-item {:key 4} "Separated link"))))) 18 | -------------------------------------------------------------------------------- /dev/snippets/button/group.cljs: -------------------------------------------------------------------------------- 1 | ;; (:require [om-bootstrap.button :as b]) 2 | 3 | (b/toolbar {} 4 | (b/button {} "Default") 5 | (b/button {:bs-style "primary"} "Primary") 6 | (b/button {:bs-style "success"} "Success") 7 | (b/button {:bs-style "info"} "Info") 8 | (b/button {:bs-style "warning"} "Warning") 9 | (b/button {:bs-style "danger"} "Danger") 10 | (b/button {:bs-style "link"} "Link")) 11 | -------------------------------------------------------------------------------- /dev/snippets/button/group_basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b]) 3 | 4 | (b/button-group {} 5 | (b/button {} "Left") 6 | (b/button {} "Middle") 7 | (b/button {} "Right")) 8 | -------------------------------------------------------------------------------- /dev/snippets/button/group_justified.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b]) 3 | 4 | (b/button-group 5 | {:justified? true} 6 | (b/button {:href "#"} "Left") 7 | (b/button {:href "#"} "Middle") 8 | (b/dropdown {:title "Dropdown"} 9 | (b/menu-item {:key 1} "Dropdown link") 10 | (b/menu-item {:key 2} "Dropdown link"))) 11 | -------------------------------------------------------------------------------- /dev/snippets/button/group_nested.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b]) 3 | 4 | (b/button-group 5 | {} 6 | (b/button {} "1") 7 | (b/button {} "2") 8 | (b/dropdown {:title "Dropdown"} 9 | (b/menu-item {:key 1} "Dropdown link") 10 | (b/menu-item {:key 2} "Dropdown link"))) 11 | -------------------------------------------------------------------------------- /dev/snippets/button/group_sizes.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b]) 3 | 4 | (let [buttons (for [s ["Left" "Middle" "Right"]] 5 | (b/button {} s))] 6 | (b/toolbar {} 7 | (b/toolbar {} (b/button-group {:bs-size "large"} buttons)) 8 | (b/toolbar {} (b/button-group {} buttons)) 9 | (b/toolbar {} (b/button-group {:bs-size "small"} buttons)) 10 | (b/toolbar {} (b/button-group {:bs-size "xsmall"} buttons)))) 11 | -------------------------------------------------------------------------------- /dev/snippets/button/group_vertical.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b]) 3 | 4 | (b/button-group 5 | {:vertical? true} 6 | (b/button {} "Button") 7 | (b/button {} "Button") 8 | (b/dropdown {:title "Dropdown"} 9 | (b/menu-item {:key 1} "Dropdown link") 10 | (b/menu-item {:key 2} "Dropdown link")) 11 | (b/button {} "Button") 12 | (b/button {} "Button") 13 | (b/dropdown {:title "Dropdown"} 14 | (b/menu-item {:key 1} "Dropdown link") 15 | (b/menu-item {:key 2} "Dropdown link")) 16 | (b/dropdown {:title "Dropdown"} 17 | (b/menu-item {:key 1} "Dropdown link") 18 | (b/menu-item {:key 2} "Dropdown link"))) 19 | -------------------------------------------------------------------------------- /dev/snippets/button/loading.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b] 3 | [om-bootstrap.mixins :as m] 4 | [om-tools.core :refer-macros [defcomponentk]] 5 | [om-tools.dom :as d :include-macros true]) 6 | 7 | (defcomponentk loading-button [state owner] 8 | (:mixins m/set-timeout-mixin) 9 | (init-state [_] {:loading? false}) 10 | (render-state 11 | [_ {:keys [loading?]}] 12 | (let [toggle #(swap! state update-in [:loading?] not) 13 | 14 | ;; This is required to get around 15 | ;; https://github.com/Prismatic/om-tools/issues/29. 16 | set-timeout (aget owner "set_timeout") 17 | handle-click (fn [e] 18 | (toggle) 19 | (set-timeout toggle 2000))] 20 | (b/button {:bs-style "primary" 21 | :disabled? loading? 22 | :on-click (when-not loading? 23 | handle-click)} 24 | (if loading? 25 | "Loading..." 26 | "Loading state"))))) 27 | 28 | (->loading-button {}) 29 | -------------------------------------------------------------------------------- /dev/snippets/button/sizes.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (d/div 6 | (b/toolbar {} 7 | (b/button {:bs-style "primary" :bs-size "large"} "Large button") 8 | (b/button {:bs-size "large"} "Large button")) 9 | (b/toolbar {} 10 | (b/button {:bs-style "primary"} "Default button") 11 | (b/button {} "Default button")) 12 | (b/toolbar {} 13 | (b/button {:bs-style "primary" :bs-size "small"} "Small button") 14 | (b/button {:bs-size "small"} "Small button")) 15 | (b/toolbar {} 16 | (b/button {:bs-style "primary" :bs-size "xsmall"} "Extra small button") 17 | (b/button {:bs-size "xsmall"} "Extra small button"))) 18 | -------------------------------------------------------------------------------- /dev/snippets/button/split_basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b]) 3 | 4 | (b/toolbar 5 | {} 6 | (for [title ["Default" "Primary" "Success" "Info" "Warning" "Danger"] 7 | :let [style (.toLowerCase title)]] 8 | (b/split 9 | {:bs-style style, :title title} 10 | (b/menu-item {:key 1} "Action") 11 | (b/menu-item {:key 2} "Another action") 12 | (b/menu-item {:key 3} "Something else here") 13 | (b/menu-item {:divider? true}) 14 | (b/menu-item {:key 4} "Separated link")))) 15 | -------------------------------------------------------------------------------- /dev/snippets/button/split_dropup.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (d/div 6 | (b/toolbar 7 | {} 8 | (b/split {:title "Dropup", :dropup? true} 9 | (b/menu-item {:key 1} "Action") 10 | (b/menu-item {:key 2} "Another action") 11 | (b/menu-item {:key 3} "Something else here") 12 | (b/menu-item {:divider? true}) 13 | (b/menu-item {:key 4} "Separated link"))) 14 | (b/toolbar 15 | {} 16 | (b/split {:title "Right dropup" 17 | :bs-style "primary" 18 | :dropup? true 19 | :pull-right? true} 20 | (b/menu-item {:key 1} "Action") 21 | (b/menu-item {:key 2} "Another action") 22 | (b/menu-item {:key 3} "Something else here") 23 | (b/menu-item {:divider? true}) 24 | (b/menu-item {:key 4} "Separated link")))) 25 | -------------------------------------------------------------------------------- /dev/snippets/button/split_right.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b]) 3 | 4 | (b/split {:title "Dropdown right", :pull-right? true} 5 | (b/menu-item {:key 1} "Action") 6 | (b/menu-item {:key 2} "Another action") 7 | (b/menu-item {:key 3} "Something else here") 8 | (b/menu-item {:divider? true}) 9 | (b/menu-item {:key 4} "Separated link")) 10 | -------------------------------------------------------------------------------- /dev/snippets/button/tag_types.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b]) 3 | 4 | (b/toolbar {} 5 | (b/button {:href "#"} "Link") 6 | (b/button {} "Button")) 7 | -------------------------------------------------------------------------------- /dev/snippets/button/toolbar_basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b]) 3 | 4 | (b/toolbar {} 5 | (b/button-group {} (for [i (range 4)] 6 | (b/button {} (str (inc i))))) 7 | (b/button-group {} (for [i (range 4 7)] 8 | (b/button {} (str (inc i))))) 9 | (b/button-group {} (b/button {} 8))) 10 | -------------------------------------------------------------------------------- /dev/snippets/button/types.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b]) 3 | 4 | (b/toolbar {} 5 | (b/button {} "Default") 6 | (b/button {:bs-style "primary"} "Primary") 7 | (b/button {:bs-style "success"} "Success") 8 | (b/button {:bs-style "info"} "Info") 9 | (b/button {:bs-style "warning"} "Warning") 10 | (b/button {:bs-style "danger"} "Danger") 11 | (b/button {:bs-style "link"} "Link")) 12 | -------------------------------------------------------------------------------- /dev/snippets/glyphicon.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b] 3 | [om-bootstrap.random :as r]) 4 | 5 | (d/div 6 | (b/toolbar 7 | {} 8 | (b/button-group 9 | {} 10 | (b/button {} (r/glyphicon {:glyph "align-left"})) 11 | (b/button {} (r/glyphicon {:glyph "align-center"})) 12 | (b/button {} (r/glyphicon {:glyph "align-right"})) 13 | (b/button {} (r/glyphicon {:glyph "align-justify"})))) 14 | (b/toolbar 15 | {} 16 | (b/button-group 17 | {} 18 | (b/button {:bs-size "large"} (r/glyphicon {:glyph "star"}) " Star") 19 | (b/button {} (r/glyphicon {:glyph "star"}) " Star") 20 | (b/button {:bs-size "small"} (r/glyphicon {:glyph "star"}) " Star") 21 | (b/button {:bs-size "xsmall"} (r/glyphicon {:glyph "star"}) " Star")))) 22 | -------------------------------------------------------------------------------- /dev/snippets/grid.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.grid :as g] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (d/div 6 | {:class "grids-examples"} 7 | (g/grid {} 8 | (g/row {:class "show-grid"} 9 | (g/col {:xs 12 :md 8} 10 | (d/code {} "(g/col {:xs 12 :md 8})")) 11 | (g/col {:xs 6 :md 4} 12 | (d/code {} "(g/col {:xs 6 :md 4})"))) 13 | (g/row {:class "show-grid"} 14 | (g/col {:xs 6 :md 4} 15 | (d/code {} "(g/col {:xs 6 :md 4})")) 16 | (g/col {:xs 6 :md 4} 17 | (d/code {} "(g/col {:xs 6 :md 4})")) 18 | (g/col {:xs 6 :md 4} 19 | (d/code {} "(g/col {:xs 6 :md 4})"))) 20 | (g/row {:class "show-grid"} 21 | (g/col {:xs 6 :xs-offset 6} 22 | (d/code {} "(g/col {:xs 6 :xs-offset 6})"))) 23 | (g/row {:class "show-grid"} 24 | (g/col {:md 6 :md-push 6} 25 | (d/code {} "(g/col {:md 6 :md-push 6})")) 26 | (g/col {:md 6 :md-pull 6} 27 | (d/code {} "(g/col {:md 6 :md-push 6})"))))) 28 | -------------------------------------------------------------------------------- /dev/snippets/input/addons.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.input :as i] 3 | [om-bootstrap.button :as b] 4 | [om-tools.dom :as d :include-macros true]) 5 | 6 | (d/form 7 | (i/input {:type "text" :addon-before "@"}) 8 | (i/input {:type "text" :addon-after ".00"}) 9 | (i/input {:type "text" :addon-before "$" :addon-after ".00"}) 10 | (i/input {:type "text" :addon-button-before 11 | (b/button {:bs-style "primary" :onClick #(js/alert "hi!")} "Click Me!")}) 12 | (i/input {:type "text" :addon-button-after 13 | (b/button {:bs-style "primary" :onClick #(js/alert "hi!")} "Click Me!")})) 14 | -------------------------------------------------------------------------------- /dev/snippets/input/feedback.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.input :as i] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (d/form 6 | (i/input {:type "text" :bs-style "success" :label "Success" :feedback? true}) 7 | (i/input {:type "text" :bs-style "warning" :label "Warning" :feedback? true}) 8 | (i/input {:type "text" :bs-style "error" :label "Error" :feedback? true})) 9 | -------------------------------------------------------------------------------- /dev/snippets/input/horizontal.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.input :as i] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (d/form {:class "form-horizontal"} 6 | (i/input {:type "text" :label "Text" 7 | :label-classname "col-xs-2" 8 | :wrapper-classname "col-xs-10"}) 9 | (i/input {:type "textarea" :label "Text Area" 10 | :label-classname "col-xs-2" 11 | :wrapper-classname "col-xs-10"}) 12 | (i/input {:type "checkbox" :label "Checkbox" 13 | :label-classname "col-xs-2" 14 | :wrapper-classname "col-xs-offset-2 col-xs-10" 15 | :help "Offset is applied to the wrapper."})) 16 | -------------------------------------------------------------------------------- /dev/snippets/input/types.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.input :as i] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (d/form 6 | (i/input {:type "text" :default-value "text"}) 7 | (i/input {:type "password" :default-value "secret"}) 8 | (i/input {:type "checkbox" 9 | :label "checkbox" 10 | ;; These attributes pass through to the internal input 11 | ;; component. :read-only is allowed instead of :readOnly 12 | ;; because om-tools camelcases dashed attributes. 13 | :checked true 14 | :read-only true}) 15 | (i/input {:type "radio" :label "radio" :checked true :read-only true}) 16 | (i/input {:type "select" :default-value "select"} 17 | (d/option {:value "select"} "select") 18 | (d/option {:value "other"} "...")) 19 | (i/input {:type "select" :multiple true} 20 | (d/option {:value "select"} "select") 21 | (d/option {:value "other"} "...")) 22 | (i/input {:type "textarea" :default-value "textarea"}) 23 | (i/input {:type "static" :value "Static Text"})) 24 | -------------------------------------------------------------------------------- /dev/snippets/input/validation.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.input :as i] 3 | [om-tools.core :refer-macros [defcomponentk]]) 4 | 5 | (defn validation-state 6 | "Returns a Bootstrap :bs-style string based on the supplied string 7 | length." 8 | [s] 9 | (let [l (count s)] 10 | (cond (> l 10) "success" 11 | (> l 5) "warning" 12 | (pos? l) "error" 13 | :else nil))) 14 | 15 | (defn handle-change 16 | "Grab the input element via the `input` reference." 17 | [owner state] 18 | (let [node (om/get-node owner "input")] 19 | (swap! state assoc :text (.-value node)))) 20 | 21 | (defcomponentk example-input [owner state] 22 | (init-state [_] {:text ""}) 23 | (render [_] 24 | (i/input 25 | {:feedback? true 26 | :type "text" 27 | :value (:text @state) 28 | :label "Working example with validation" 29 | :placeholder "Enter text" 30 | :help "Validates based on string length." 31 | :group-classname "group-class" 32 | :wrapper-classname "wrapper-class" 33 | :label-classname "label-class" 34 | :bs-style (validation-state (:text @state)) 35 | :on-change #(handle-change owner state)}))) 36 | 37 | (->example-input {}) 38 | -------------------------------------------------------------------------------- /dev/snippets/input/wrapper.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.grid :as g] 3 | [om-bootstrap.input :as i]) 4 | 5 | (i/input {:label "Input wrapper" 6 | :help "Use this when you need something other than the 7 | available input types."} 8 | (g/row 9 | {} 10 | (g/col {:xs 6} (i/input {:type "text" :class "form-control"})) 11 | (g/col {:xs 6} (i/input {:type "text" :class "form-control"})))) 12 | -------------------------------------------------------------------------------- /dev/snippets/jumbotron/basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b] 3 | [om-bootstrap.random :as r] 4 | [om-tools.dom :as d :include-macros true]) 5 | 6 | (r/jumbotron {} 7 | (d/h1 "Hello, World!") 8 | (d/p "This is a simple hero unit, a simple 9 | jumbotron-style component for calling extra attention to 10 | featured content or information.") 11 | (d/p (b/button {:bs-style "primary"} "Learn More"))) 12 | -------------------------------------------------------------------------------- /dev/snippets/label/basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.random :as r] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (d/div 6 | (d/h1 "Label " (r/label {} "New")) 7 | (d/h2 "Label " (r/label {} "New")) 8 | (d/h3 "Label " (r/label {} "New")) 9 | (d/h4 "Label " (r/label {} "New")) 10 | (d/h5 "Label " (r/label {} "New")) 11 | (d/p "Label " (r/label {} "New"))) 12 | -------------------------------------------------------------------------------- /dev/snippets/label/variations.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.random :as r] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (d/div 6 | (r/label {:bs-style "default"} "Default") 7 | (r/label {:bs-style "primary"} "Primary") 8 | (r/label {:bs-style "success"} "Success") 9 | (r/label {:bs-style "info"} "Info") 10 | (r/label {:bs-style "warning"} "Warning") 11 | (r/label {:bs-style "danger"} "Danger")) 12 | -------------------------------------------------------------------------------- /dev/snippets/modal/live.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.modal :as md]) 3 | 4 | (defn trigger [app-state owner] 5 | (reify 6 | om/IInitState 7 | (init-state [_] 8 | {:visible? false}) 9 | om/IRender 10 | (render [_] 11 | (d/div 12 | (md/modal {:header (d/h4 "This is a Modal") 13 | :footer (d/div (b/button {} "Save") 14 | (b/button {} "Send")) 15 | :close-button? true 16 | :visible? (om/get-state owner :visible?)} 17 | "This is in the modal body") 18 | (b/button {:bs-style "primary" 19 | :bs-size "large" 20 | :on-click (fn [_] (om/set-state! owner :visible? true))} 21 | "Click to open Modal"))))) 22 | 23 | (om/build trigger {}) -------------------------------------------------------------------------------- /dev/snippets/modal/static.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.modal :as md]) 3 | 4 | (md/modal {:header (d/h4 "This is a Modal") 5 | :footer (b/button {} "Save") 6 | :close-button? true 7 | :visible? true} 8 | "This should be in the Modal body") -------------------------------------------------------------------------------- /dev/snippets/nav/bar_basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.button :as b] 3 | [om-bootstrap.nav :as n] 4 | [om-tools.dom :as d :include-macros true]) 5 | 6 | (n/navbar 7 | {:brand (d/a {:href "#"} 8 | "Navbar")} 9 | (n/nav 10 | {:collapsible? true} 11 | (n/nav-item {:key 1 :href "#"} "Link") 12 | (n/nav-item {:key 2 :href "#"} "Link") 13 | (b/dropdown {:key 3, :title "Dropdown"} 14 | (b/menu-item {:key 1} "Action") 15 | (b/menu-item {:key 2} "Another action") 16 | (b/menu-item {:key 3} "Something else here") 17 | (b/menu-item {:divider? true}) 18 | (b/menu-item {:key 4} "Separated link")) 19 | :right 20 | (n/nav-item {:key 1 :href "#"} "Right"))) 21 | -------------------------------------------------------------------------------- /dev/snippets/nav/pills.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.nav :as n]) 3 | 4 | (n/nav {:bs-style "pills" 5 | :active-key 1 6 | :on-select (fn [k _] (js/alert (str "Selected " k)))} 7 | (n/nav-item {:key 1 :href "/home"} 8 | "nav-item 1 content") 9 | (n/nav-item {:key 2 :href "/home"} 10 | "nav-item 2 content") 11 | (n/nav-item {:key 3 :href "/home" :disabled? true} 12 | "nav-item 3 content")) 13 | -------------------------------------------------------------------------------- /dev/snippets/nav/tabs.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.nav :as n]) 3 | 4 | (n/nav {:bs-style "tabs" 5 | :active-key 1 6 | :on-select (fn [k _] (js/alert (str "Selected " k)))} 7 | (n/nav-item {:key 1 :href "/home"} 8 | "nav-item 1 content") 9 | (n/nav-item {:key 2 :href "/home"} 10 | "nav-item 2 content") 11 | (n/nav-item {:key 3 :href "/home" :disabled? true} 12 | "nav-item 3 content")) 13 | -------------------------------------------------------------------------------- /dev/snippets/page_header.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.random :as r] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (r/page-header {} "Example page header " 6 | (d/small "Subtext for header")) 7 | -------------------------------------------------------------------------------- /dev/snippets/pagination/active.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.pagination :as pg]) 3 | 4 | (pg/pagination {} 5 | (pg/previous {:disabled? true}) 6 | (pg/page {} "1") 7 | (pg/page {} "2") 8 | (pg/page {:active? true} "3") 9 | (pg/next {})) 10 | -------------------------------------------------------------------------------- /dev/snippets/pagination/basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.pagination :as pg]) 3 | 4 | (pg/pagination {} 5 | (pg/page {} "1") 6 | (pg/page {} "2") 7 | (pg/page {} "3")) 8 | -------------------------------------------------------------------------------- /dev/snippets/pagination/centered.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.pagination :as pg]) 3 | 4 | (pg/pagination {:class "text-center"} 5 | (pg/page {} "1") 6 | (pg/page {} "2") 7 | (pg/page {} "3")) 8 | -------------------------------------------------------------------------------- /dev/snippets/pagination/disabled.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.pagination :as pg]) 3 | 4 | (pg/pagination {} 5 | (pg/previous {:disabled? true}) 6 | (pg/page {} "1") 7 | (pg/page {} "2") 8 | (pg/page {} "3") 9 | (pg/next {})) 10 | -------------------------------------------------------------------------------- /dev/snippets/pagination/navigation.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.pagination :as pg]) 3 | 4 | (pg/pagination {} 5 | (pg/previous {}) 6 | (pg/page {} "1") 7 | (pg/page {} "2") 8 | (pg/page {} "3") 9 | (pg/next {})) 10 | -------------------------------------------------------------------------------- /dev/snippets/panel/basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.panel :as p]) 3 | 4 | (p/panel {} "Basic panel example.") 5 | -------------------------------------------------------------------------------- /dev/snippets/panel/collapsible.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.panel :as p]) 3 | 4 | (p/panel {:header "Collapse Me!" 5 | :collapsible? true} 6 | (d/span "Sometimes I'm here, sometimes I'm not!")) 7 | -------------------------------------------------------------------------------- /dev/snippets/panel/contextual.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.panel :as p] 3 | [om-bootstrap.dom :as d :include-macros true]) 4 | 5 | (for [style [nil "primary" "success" "info" "warning" "danger"]] 6 | (p/panel (merge {:header (d/h3 "Panel title")} 7 | (when style {:bs-style style})) 8 | "Panel content")) 9 | -------------------------------------------------------------------------------- /dev/snippets/panel/footer.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.panel :as p]) 3 | 4 | (p/panel {:footer "Panel footer"} "Panel content") 5 | -------------------------------------------------------------------------------- /dev/snippets/panel/group_accordion.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.panel :as p]) 3 | 4 | (p/panel {} "Basic panel example.") 5 | -------------------------------------------------------------------------------- /dev/snippets/panel/group_controlled.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.panel :as p]) 3 | 4 | (p/panel {} "Basic panel example.") 5 | -------------------------------------------------------------------------------- /dev/snippets/panel/group_uncontrolled.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.panel :as p]) 3 | 4 | (p/panel {} "Basic panel example.") 5 | -------------------------------------------------------------------------------- /dev/snippets/panel/heading.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.panel :as p] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (d/div 6 | (p/panel {:header "Panel heading without title"} 7 | "Panel content") 8 | (p/panel {:header (d/h3 "Panel title")} 9 | "Panel content")) 10 | -------------------------------------------------------------------------------- /dev/snippets/panel/list-group.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.panel :as p] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (p/panel 6 | {:header "List group panel" 7 | :list-group (d/ul {:class "list-group"} 8 | (d/li {:class "list-group-item"} "Item 1") 9 | (d/li {:class "list-group-item"} "Item 2") 10 | (d/li {:class "list-group-item"} "Item 3"))} 11 | nil) 12 | -------------------------------------------------------------------------------- /dev/snippets/popover/basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.random :as r] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (d/div {:style {:height 120}} 6 | (r/popover {:placement "right" 7 | :position-left 200 8 | :position-top 50 9 | :title "Popover right"} 10 | "And here's some " 11 | (d/strong "amazing") 12 | " content. It's very engaging. Right?")) 13 | -------------------------------------------------------------------------------- /dev/snippets/progressbar/active.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.progress-bar :as pb]) 3 | 4 | (pb/progress-bar {:now 70 :active? true}) -------------------------------------------------------------------------------- /dev/snippets/progressbar/basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.progress-bar :as pb]) 3 | 4 | (pb/progress-bar {:min 0 :max 100 :now 50}) -------------------------------------------------------------------------------- /dev/snippets/progressbar/contextual.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.progress-bar :as pb]) 3 | 4 | (for [context [nil "primary" "success" "info" "warning" "danger"]] 5 | (pb/progress-bar (merge {:now 50 :label "50%"} 6 | (when context {:bs-style context})))) -------------------------------------------------------------------------------- /dev/snippets/progressbar/label.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.progress-bar :as pb]) 3 | 4 | (pb/progress-bar {:min 0 :max 100 :now 50 :label "Loading"}) -------------------------------------------------------------------------------- /dev/snippets/progressbar/sr_only_label.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.progress-bar :as pb]) 3 | 4 | (pb/progress-bar {:min 0 :max 100 :now 50 :label "50%" :sr-only? true}) -------------------------------------------------------------------------------- /dev/snippets/progressbar/stacked.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.progress-bar :as pb]) 3 | 4 | (pb/progress-bar {} 5 | (pb/progress-bar {:now 35 :bs-style "success" :nested? true}) 6 | (pb/progress-bar {:now 20 :bs-style "warning" :striped? true :nested? true}) 7 | (pb/progress-bar {:now 10 :bs-style "danger" :nested? true})) 8 | -------------------------------------------------------------------------------- /dev/snippets/progressbar/striped.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.progress-bar :as pb]) 3 | 4 | (pb/progress-bar {:now 70 :striped? true}) -------------------------------------------------------------------------------- /dev/snippets/table/basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.table :refer [table]] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (table {:striped? true :bordered? true :condensed? true :hover? true} 6 | (d/thead 7 | (d/tr 8 | (d/th "#") 9 | (d/th "First Name") 10 | (d/th "Last Name") 11 | (d/th "Username"))) 12 | (d/tbody 13 | (d/tr 14 | (d/td "1") 15 | (d/td "Mark") 16 | (d/td "Otto") 17 | (d/td "@mdo")) 18 | (d/tr 19 | (d/td "2") 20 | (d/td "Jacob") 21 | (d/td "Thornton") 22 | (d/td "@fat")) 23 | (d/tr 24 | (d/td "3") 25 | (d/td {:col-span 2} "Larry the Bird") 26 | (d/td "@twitter")))) 27 | -------------------------------------------------------------------------------- /dev/snippets/table/responsive.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.table :refer [table]] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (table {:responsive? true} 6 | (d/thead 7 | (d/tr 8 | (d/th "#") 9 | (repeat 6 (d/th "Table heading"))) 10 | (d/tbody 11 | (for [i (range 3)] 12 | (d/tr 13 | (d/td (str (inc i))) 14 | (repeat 6 (d/td "Table cell"))))))) 15 | -------------------------------------------------------------------------------- /dev/snippets/tooltip/basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.random :as r] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (d/div {:style {:height 50}} 6 | (r/tooltip {:placement "right" 7 | :position-left 150 8 | :position-top 50} 9 | (d/strong "Holy guacamole!") 10 | " Check this info.")) 11 | -------------------------------------------------------------------------------- /dev/snippets/well/basic.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.random :as r]) 3 | 4 | (r/well {} "Look, I'm in a well!") 5 | -------------------------------------------------------------------------------- /dev/snippets/well/sizes.cljs: -------------------------------------------------------------------------------- 1 | #_ 2 | (:require [om-bootstrap.random :as r] 3 | [om-tools.dom :as d :include-macros true]) 4 | 5 | (d/div 6 | (r/well {:bs-size "large"} "Look, I'm in a large well!") 7 | (r/well {:bs-size "small"} "Look, I'm in a small well!")) 8 | -------------------------------------------------------------------------------- /docs/src/clj/om_bootstrap/macros.clj: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.macros 2 | (:require [clojure.java.io :as io] 3 | [clojure.string :as s])) 4 | 5 | (defmacro slurp-example 6 | "Takes a snippet name and returns a map with the code string under 7 | `:code`, and the evaluated body under `:body`." 8 | [snippet] 9 | (let [s (slurp (io/resource (format "snippets/%s.cljs" snippet)))] 10 | `(do {:code ~(s/replace s "#_\n" "") 11 | :body ~(read-string (str "(do " s ")"))}))) 12 | -------------------------------------------------------------------------------- /docs/src/clj/om_bootstrap/server.clj: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.server 2 | (:gen-class) 3 | (:require [clojure.java.io :as io] 4 | [compojure.handler :as handler] 5 | [compojure.route :as route] 6 | [compojure.core :refer [GET defroutes]] 7 | [hiccup.page :as h] 8 | [hiccup.element :as e] 9 | [org.httpkit.server :refer [run-server]])) 10 | 11 | (defn mode 12 | "Returns the current server mode." 13 | [] 14 | (or (keyword (System/getenv "RING_ENV")) 15 | :dev)) 16 | 17 | (defn dev? [] 18 | (= :dev (mode))) 19 | 20 | (defn clojurescript [] 21 | (if (dev?) 22 | (list 23 | (h/include-js "static/generated/goog/base.js") 24 | (h/include-js "static/assets/main.js") 25 | (e/javascript-tag "goog.require(\"om_bootstrap.docs\");")) 26 | (h/include-js "static/assets/generated/om_bootstrap.js"))) 27 | 28 | (defn index [] 29 | (h/html5 30 | [:head [:title "Om Bootstrap"] 31 | [:meta {:http-equiv "X-UI-Compatible" :content "IE=edge"}] 32 | [:meta {:name "viewport" :content "width=device-width, initial-scale=1.0"}] 33 | (h/include-css "static/vendor/bootstrap/bootstrap.css") 34 | (h/include-css "static/vendor/bootstrap/docs.css") 35 | (h/include-css "static/vendor/highlight/solarized.css") 36 | (h/include-css "static/assets/style.css") 37 | ""] 44 | [:body 45 | [:div#app] 46 | (h/include-js "static/vendor/highlight/highlight.pack.js") 47 | (clojurescript)])) 48 | 49 | (defroutes app-routes 50 | (route/resources "/static") 51 | (GET "/*" [] (index))) 52 | 53 | (defonce server 54 | (atom nil)) 55 | 56 | (defn -main 57 | "Boots up a server that redirects everything to the client side." 58 | [] 59 | (let [port (or (when-let [port-env (System/getenv "PORT")] 60 | (Integer/parseInt port-env)) 61 | 8080)] 62 | (when-let [f @server] 63 | (println "Killing existing server.") 64 | (f)) 65 | (reset! server (run-server (handler/api #'app-routes) 66 | {:port port})) 67 | (println "Server started on port [" port "]."))) 68 | -------------------------------------------------------------------------------- /docs/src/cljs/om_bootstrap/docs.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.docs 2 | (:require [cljs.core.async :as a :refer [chan put!]] 3 | [goog.events :as ev] 4 | [om.core :as om :include-macros true] 5 | [om-bootstrap.docs.footer :refer [footer]] 6 | [om-bootstrap.docs.nav :as n] 7 | [om-bootstrap.docs.components :refer [components-page]] 8 | [om-bootstrap.docs.getting-started :refer [getting-started-page]] 9 | [om-bootstrap.docs.home :refer [home-page]] 10 | [om-bootstrap.docs.shared :refer [four-oh-four]] 11 | [om-tools.core :refer-macros [defcomponentk]] 12 | [om-tools.dom :as d :include-macros true] 13 | [secretary.core :as route :refer-macros [defroute]]) 14 | (:require-macros [cljs.core.async.macros :refer [go-loop]]) 15 | (:import [goog.history EventType])) 16 | 17 | (defn shell [active-page guts] 18 | (d/div {} 19 | (n/nav-main active-page) 20 | guts 21 | (footer))) 22 | 23 | (defcomponentk app 24 | "This is the top level component that renders the entire example 25 | docs page." 26 | [[:data active-page]] 27 | (render [_] 28 | (shell active-page 29 | (case active-page 30 | "not-found" (four-oh-four) 31 | "root" (home-page) 32 | "getting-started" (getting-started-page) 33 | "components" (components-page))))) 34 | 35 | (defn load-om [component state] 36 | (om/root component state 37 | {:target (. js/document (getElementById "app"))})) 38 | 39 | ;; ## Client Side Routing and Navigation 40 | 41 | (defroute "/" [] 42 | (load-om app {:active-page "root"})) 43 | 44 | (defroute "/getting-started" [] 45 | (load-om app {:active-page "getting-started"})) 46 | 47 | (defroute "/components" [] 48 | (load-om app {:active-page "components"})) 49 | 50 | (defroute "*" [] 51 | (load-om app {:active-page "not-found"})) 52 | 53 | (defn listen 54 | "Registers a listener of type `type` on the supplied 55 | element. Returns a channel that contains events." 56 | [el type] 57 | (let [out (chan)] 58 | (ev/listen el type (fn [e] (put! out e))) 59 | out)) 60 | 61 | (defn setup-app 62 | "Sets up an event loop that listens for client side " 63 | [] 64 | (let [nav (listen n/history (.-NAVIGATE EventType))] 65 | (go-loop [] 66 | (let [token (.-token (a/ js/window .-location .-pathname)) 74 | (setup-app)) 75 | 76 | (on-load) 77 | -------------------------------------------------------------------------------- /docs/src/cljs/om_bootstrap/docs/example.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.docs.example 2 | (:require [om.core :as om :include-macros true] 3 | [om-bootstrap.util :as u] 4 | [om-tools.core :refer-macros [defcomponentk]] 5 | [om-tools.dom :as d :include-macros true])) 6 | 7 | (defn bs-example 8 | ([item] (d/div {:class "bs-example"} item)) 9 | ([props item] 10 | (d/div (u/merge-props props {:class "bs-example"}) 11 | item))) 12 | 13 | (defcomponentk code-block 14 | "Generates a component" 15 | [[:data code {language "clojure"}] owner] 16 | (did-mount [_] 17 | (let [block (om/get-node owner "highlight")] 18 | (.highlightBlock js/hljs block))) 19 | (will-unmount [_]) 20 | (render [_] 21 | (let [code-opts (if language {:class language} {})] 22 | (d/div 23 | {:class "highlight solarized-light-wrapper"} 24 | (d/pre {:ref "highlight"} 25 | (d/code code-opts code)))))) 26 | 27 | (defcomponentk example 28 | [[:data body code] state] 29 | (init-state [_] {:open? false}) 30 | (render-state 31 | [_ {:keys [open?]}] 32 | (d/div {:class "playground"} 33 | (bs-example body) 34 | (when open? 35 | (->code-block {:code code})) 36 | (d/a {:href "#" 37 | :class (d/class-set 38 | {:code-toggle true 39 | :open open?}) 40 | :on-click (fn [e] 41 | (swap! state update-in [:open?] not) 42 | (.preventDefault e))} 43 | (if open? 44 | "hide code" 45 | "show code"))))) 46 | 47 | (defn TODO [] 48 | (->example {:code "TODO" :body (d/p "TODO")})) 49 | -------------------------------------------------------------------------------- /docs/src/cljs/om_bootstrap/docs/footer.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.docs.footer 2 | (:require [om-tools.dom :as d :include-macros true])) 3 | 4 | (defn footer [] 5 | (d/footer 6 | {:class "bs-docs-footer" :role "contentinfo"} 7 | (d/div 8 | {:class "container"} 9 | (d/div 10 | {:class "bs-docs-social"} 11 | (d/ul 12 | {:class "bs-docs-social-buttons"} 13 | (d/li 14 | (d/iframe 15 | {:class "github-btn" 16 | :width 92 17 | :height 20 18 | :title "Star on Github" 19 | :src "http://ghbtns.com/github-btn.html?user=racehub&repo=om-bootstrap&type=watch&count=true"})) 20 | (d/li 21 | (d/iframe 22 | {:class "github-btn" 23 | :width 92 24 | :height 20 25 | :title "Fork on Github" 26 | :src "http://ghbtns.com/github-btn.html?user=racehub&repo=om-bootstrap&type=fork&count=true"})))) 27 | (d/p 28 | "Code licensed under " 29 | (d/a 30 | {:href "https://github.com/racehub/om-bootstrap/blob/master/LICENSE" 31 | :target "_blank"} "MIT") ".") 32 | (d/ul 33 | {:class "bs-docs-footer-links muted"} 34 | (d/li 35 | (d/a {:href "https://github.com/racehub/om-bootstrap"} 36 | "GitHub")) 37 | (d/li "·") 38 | (d/li 39 | (d/a {:href 40 | "https://github.com/racehub/om-bootstrap/issues?state=open"} 41 | "Issues")) 42 | (d/li "·") 43 | (d/li 44 | (d/a {:href "https://github.com/racehub/om-bootstrap/releases"} 45 | "Releases")))))) 46 | -------------------------------------------------------------------------------- /docs/src/cljs/om_bootstrap/docs/getting_started.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.docs.getting-started 2 | "Code for the getting started page." 3 | (:require [om-bootstrap.docs.example :refer [->code-block]] 4 | [om-bootstrap.docs.shared :refer [page-header]] 5 | [om-tools.dom :as d :include-macros true])) 6 | 7 | 8 | (defn getting-started-page [] 9 | [(page-header 10 | {:title "Getting started" 11 | :subtitle "An overview of how to install and use Om-Bootstrap."}) 12 | (d/div {:class "container bs-docs-container"} 13 | (d/div 14 | {:class "row"} 15 | (d/div {:class "col-md-9" 16 | :role "main"} 17 | (d/div 18 | {:class "bs-docs-section"} 19 | (d/h2 {:id "setup" 20 | :class "page-header"} 21 | "Setup") 22 | (d/p {:class "lead"} "Om-Bootstrap is a library that makes it easy to use " 23 | (d/a {:href "http://getbootstrap.com"} "Bootstrap's") " fantastic CSS elements and grid layout with " 24 | (d/a {:href "https://github.com/swannodette/om"} "Om")" and ClojureScript. This section describes how to configure Leiningen and the " 25 | (d/a {:href "http://github.com/emezeske/lein-cljsbuild"} "lein-cljsbuild") " plugin to get your first Om-Bootstrap project started.") 26 | (d/h3 "Leiningen") 27 | (d/p "You'll need " (d/a {:href "http://leiningen.org/"} "Leiningen") 28 | " installed to build your Clojurescript project. Your " (d/code "project.clj") 29 | " should include Clojure, ClojureScript, Om-Bootstrap and a supported version of " 30 | (d/a {:href "https://github.com/swannodette/om"} "Om") ":") 31 | (->code-block {:code "(defproject foo \"0.1.0\" 32 | ... 33 | :dependencies [[org.clojure/clojure \"1.6.0\"] 34 | [org.clojure/clojurescript \"0.0-2760\"] 35 | [racehub/om-bootstrap \"0.5.0\"] 36 | [org.omcljs/om \"0.8.8\"]] 37 | ...)"}) 38 | (d/p "Om-Bootstrap requires Om 0.8.0 or later, and has been tested against Bootstrap 3.1.0 and later. The " 39 | (d/a {:href "https://github.com/racehub/om-bootstrap#supported-versions"} "Om-Bootstrap README") 40 | " has more information on specific requirements and limitations.") 41 | (d/p "For local development your " 42 | (d/a {:href "http://github.com/emezeske/lein-cljsbuild"} "lein-cljsbuild") 43 | " settings should look something like this:") 44 | (->code-block {:code ":cljsbuild { 45 | :builds [{:id \"dev\" 46 | :source-paths [\"src\"] 47 | :compiler { 48 | :output-to \"main.js\" 49 | :output-dir \"out\" 50 | :optimizations :none 51 | :source-map true}}]}"}) 52 | (d/p "Your local development markup should look like the following:") 53 | (->code-block {:code " 54 | 55 | 57 | 58 | 59 |
60 | 61 | 62 | 63 | 64 | "}) 65 | (d/p "(Note that you can replace the Bootstrap version here with your own.) 66 | This markup assumes that you've placed your initial Clojurescript code 67 | in a namespace called " (d/code "main.core") 68 | ". Adjust accordingly.") 69 | (d/p "For production, your " 70 | (d/a {:href "http://github.com/emezeske/lein-cljsbuild"} "lein-cljsbuild") 71 | " settings should look like this:") 72 | (->code-block {:code ":cljsbuild { 73 | :builds [{:id \"release\" 74 | :source-paths [\"src\"] 75 | :compiler { 76 | :output-to \"main.js\" 77 | :optimizations :advanced 78 | :pretty-print false}}]}"}) 79 | (d/p "This will generate a single file called " (d/code "main.js") "." 80 | "Your production markup should look something like this:") 81 | (->code-block {:code " 82 | 83 | 85 | 86 | 87 |
88 | 89 | 90 | "})) 91 | (d/div 92 | {:class "bs-docs-section"} 93 | (d/h2 {:id "browser-support" 94 | :class "page-header"} 95 | "Browser support") 96 | (d/p "We aim to support all browsers supported by both " 97 | (d/a {:href "http://facebook.github.io/react/docs/working-with-the-browser.html#browser-support-and-polyfills"} "React") 98 | " and " 99 | (d/a {:href "http://getbootstrap.com/getting-started/#support"} "Bootstrap") ".") 100 | (d/p "React requires " 101 | (d/a {:href "http://facebook.github.io/react/docs/working-with-the-browser.html#browser-support-and-polyfills"} 102 | "polyfills for non-ES5 capable browsers."))))))]) 103 | -------------------------------------------------------------------------------- /docs/src/cljs/om_bootstrap/docs/home.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.docs.home 2 | "Code for the landing page." 3 | (:require [om-bootstrap.docs.shared :refer [page-header]] 4 | [om-tools.dom :as d :include-macros true])) 5 | 6 | (defn home-page [] 7 | (d/main {:class "bs-docs-masthead" 8 | :id "content" 9 | :role "main"} 10 | (d/div {:class "container"} 11 | (d/span {:class (d/class-set {:bs-docs-booticon true 12 | :bs-docs-booticon-lg true 13 | :bs-docs-booticon-outline true})}) 14 | (d/p {:class "lead"} 15 | "The most popular front-end framework, rebuilt for Om.")))) 16 | -------------------------------------------------------------------------------- /docs/src/cljs/om_bootstrap/docs/nav.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.docs.nav 2 | (:require [om-bootstrap.nav :as n] 3 | [om-tools.dom :as d :include-macros true]) 4 | (:import [goog.history Html5History])) 5 | 6 | (def history 7 | "Instance of the HTML5 History class." 8 | (doto (Html5History.) 9 | (.setUseFragment false) 10 | (.setEnabled true))) 11 | 12 | (defn client-nav! 13 | "This trick comes from here: 14 | https://github.com/theJohnnyBrown/matchcolor/blob/master/src/matchcolor/views.cljs. 15 | 16 | This function is meant to be used as the :on-click event of an 17 | anchor tag." 18 | [e] 19 | (.setToken history 20 | (-> e .-target (.getAttribute "href")) 21 | (-> e .-target .-title)) 22 | (.preventDefault e)) 23 | 24 | 25 | (defn nav-main [active-page] 26 | (n/navbar 27 | {:component-fn (fn [opts & c] 28 | (d/header opts c)) 29 | :brand (d/a {:href "" 30 | :on-click (fn [e] 31 | (.preventDefault e) 32 | (client-nav! e))} 33 | "Om Bootstrap") 34 | :static-top? true 35 | :class "bs-docs-nav" 36 | :role "banner" 37 | :toggle-nav-key 0} 38 | (n/nav {:class "bs-navbar-collapse" 39 | :role "navigation" 40 | :key 0 41 | :id "top"} 42 | (n/nav-item {:on-select (fn [& _] 43 | (.setToken history 44 | "getting-started" 45 | "Getting started")) 46 | :href "getting-started" 47 | :active? (= "getting-started" active-page)} 48 | "Getting started") 49 | (n/nav-item {:title "Components" 50 | :href "components" 51 | :on-select (fn [& _] 52 | (.setToken history 53 | "components" 54 | "Components")) 55 | :active? (= "components" active-page)} 56 | "Components")))) 57 | -------------------------------------------------------------------------------- /docs/src/cljs/om_bootstrap/docs/shared.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.docs.shared 2 | (:require [om-tools.dom :as d :include-macros true])) 3 | 4 | (defn page-header [{:keys [title subtitle]}] 5 | (d/div {:class "bs-docs-header" :id "content"} 6 | (d/div {:class "container"} 7 | (d/h1 title) 8 | (when subtitle 9 | (d/p subtitle))))) 10 | 11 | (defn four-oh-four [] 12 | [(page-header {:title "404, Batman!"}) 13 | (d/div {:class "container bs-docs-container"} 14 | (d/div 15 | {:class "row"} 16 | (d/div 17 | {:class "col-md-9" :role "main"} 18 | (d/div 19 | {:class "bs-docs-section"} 20 | (d/h2 {:class "page-header"} 21 | "Page Not Found :(") 22 | (d/p "Try one of the links at the top to get some content, yo.")))))]) 23 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (def cljsbuild 2 | '[lein-cljsbuild "1.1.2" :exclusions [org.clojure/clojurescript]]) 3 | 4 | (def server-deps 5 | '[[javax.servlet/servlet-api "2.5"] 6 | [compojure "1.4.0"] 7 | [http-kit "2.1.19"] 8 | [hiccup "1.0.5"]]) 9 | 10 | (defproject racehub/om-bootstrap "0.6.1-SNAPSHOT" 11 | :description "Bootstrap meets Om." 12 | :url "http://github.com/racehub/om-bootstrap" 13 | :license {:name "MIT License" 14 | :url "http://www.opensource.org/licenses/mit-license.php" 15 | :distribution :repo} 16 | :scm {:name "git" 17 | :url "https://github.com/racehub/om-bootstrap"} 18 | :min-lein-version "2.3.0" 19 | :uberjar-name "om-bootstrap.jar" 20 | :jar-exclusions [#".DS_Store"] 21 | :dependencies [[org.clojure/clojure "1.8.0"] 22 | [org.clojure/core.async "0.2.374"] 23 | [prismatic/om-tools "0.3.11" :exclusions [om]] 24 | [prismatic/schema "0.4.0" 25 | :exclusions [org.clojure/clojurescript]] 26 | [org.omcljs/om "0.8.8" :scope "provided"]] 27 | :profiles {:provided 28 | {:dependencies [[org.clojure/clojurescript "1.7.228"] 29 | [secretary "1.2.3"]]} 30 | ;; Change to the first version of the uberjar profile 31 | ;; when this bug gets fixed: 32 | ;; https://github.com/technomancy/leiningen/issues/1694 33 | ;; :uberjar [:docs {}] 34 | :uberjar {:aot :all 35 | :omit-source true 36 | :main om-bootstrap.server 37 | :plugins [~cljsbuild] 38 | :prep-tasks ^:replace [["clean"] 39 | ["cljsbuild" "once" "heroku"] 40 | ["javac"] 41 | ["compile" ":all"]] 42 | :dependencies ~server-deps 43 | :source-paths ["docs/src/clj"] 44 | :resource-paths ["dev"]} 45 | :docs {:aot :all 46 | :omit-source true 47 | :main om-bootstrap.server 48 | :plugins [~cljsbuild] 49 | :prep-tasks ^:replace [["clean"] 50 | ["cljsbuild" "once" "heroku"] 51 | ["javac"] 52 | ["compile" ":all"]] 53 | :dependencies ~server-deps 54 | :source-paths ["docs/src/clj"] 55 | :resource-paths ["dev"]} 56 | :dev {:plugins [~cljsbuild 57 | [com.cemerick/clojurescript.test "0.3.1"] 58 | [paddleguru/lein-gitflow "0.1.2"] 59 | [lein-figwheel "0.5.0-6"]] 60 | :dependencies ~server-deps 61 | :source-paths ["docs/src/clj" "docs/src-dev"] 62 | :resource-paths ["dev"] 63 | :main om-bootstrap.server}} 64 | :aliases {"test" ["cljsbuild" "test"] 65 | ;; We'll change this for the next new alpha that comes out. 66 | ;; "test-8" ["do" "clean," "cljsbuild" "clean," "with-profile" "+om-8" "cljsbuild" "test"] 67 | "repl" ["do" "cljsbuild" "once" "docs," "repl"]} 68 | :cljsbuild 69 | {:test-commands {"unit" 70 | ["phantomjs" :runner 71 | "test/vendor/es5-shim.js" 72 | "test/vendor/es5-sham.js" 73 | "test/vendor/console-polyfill.js" 74 | "this.literal_js_was_evaluated=true" 75 | "target/om_bootstrap.js"]} 76 | :builds 77 | {:docs 78 | {:source-paths ["src" "docs/src/cljs" "docs/src/clj"] 79 | :figwheel true 80 | :compiler {:output-to "dev/public/assets/main.js" 81 | :output-dir "dev/public/generated" 82 | :optimizations :none 83 | :source-maps true}} 84 | :heroku 85 | {:source-paths ["src" "docs/src/cljs" "docs/src/clj"] 86 | :compiler {:output-to "dev/public/assets/generated/om_bootstrap.js" 87 | :output-dir "dev/public/assets/generated" 88 | :externs ["externs/highlight.js"] 89 | :optimizations :advanced 90 | :pretty-print false 91 | :source-map "dev/public/assets/generated/om_bootstrap.js.map"}} 92 | :test 93 | {:source-paths ["src" "test"] 94 | :compiler {:output-to "target/om_bootstrap.js" 95 | :optimizations :whitespace 96 | :pretty-print true}}}} 97 | :lein-release {:deploy-via :shell 98 | :shell ["lein" "deploy" "clojars"]}) 99 | -------------------------------------------------------------------------------- /src/om_bootstrap/button.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.button 2 | "Bootstrap buttons!" 3 | (:require [om.core :as om] 4 | [om-bootstrap.mixins :as m] 5 | [om-bootstrap.types :as t] 6 | [om-bootstrap.util :as u] 7 | [om-tools.core :refer-macros [defcomponentk]] 8 | [om-tools.dom :as d :include-macros true] 9 | [om-tools.mixin :refer-macros [defmixin]] 10 | [schema.core :as s :include-macros true])) 11 | 12 | ;; ## Basic Button 13 | 14 | (def Button 15 | (t/bootstrap 16 | {(s/optional-key :active?) s/Bool 17 | (s/optional-key :disabled?) s/Bool 18 | (s/optional-key :block?) s/Bool 19 | (s/optional-key :nav-item?) s/Bool 20 | (s/optional-key :nav-dropdown?) s/Bool})) 21 | 22 | (def ButtonGroup 23 | (t/bootstrap 24 | {(s/optional-key :vertical?) s/Bool 25 | (s/optional-key :justified?) s/Bool})) 26 | 27 | ;; ## Code 28 | 29 | (s/defn render-anchor 30 | [opts :- {:classes {s/Any s/Any} 31 | :disabled? (s/maybe s/Bool) 32 | :props {s/Any s/Any}} 33 | children] 34 | (let [props {:href (-> opts :props (:href "#")) 35 | :class (d/class-set (assoc (:classes opts) 36 | :disabled (:disabled? opts))) 37 | :role "button"}] 38 | (d/a (u/merge-props props (:props opts)) 39 | children))) 40 | 41 | 42 | (s/defn button :- t/Component 43 | "Renders a button." 44 | [props :- Button & children] 45 | (let [[bs props] (t/separate Button props {:bs-class "button" 46 | :bs-style "default" 47 | :type "button"}) 48 | klasses (if (:nav-dropdown? bs) 49 | {} 50 | (t/bs-class-set bs)) 51 | klasses (merge klasses 52 | {:active (:active? bs) 53 | :btn-block (:block? bs)})] 54 | (cond 55 | (:nav-item? bs) (d/li {:class (d/class-set {:active (:active? bs) :disabled? (:disabled? bs)})} 56 | (render-anchor {:props props 57 | :classes klasses} 58 | children)) 59 | (or (:href props) 60 | (:nav-dropdown? bs)) 61 | (render-anchor {:props props 62 | :disabled? (:disabled? bs) 63 | :classes klasses} 64 | children) 65 | :else (d/button (u/merge-props props {:class (d/class-set klasses) 66 | :disabled (:disabled? bs)}) 67 | children)))) 68 | 69 | ;; ## Button Toolbar 70 | 71 | (s/defn toolbar :- t/Component 72 | "Renders a button toolbar." 73 | [opts & children] 74 | (let [[bs props] (t/separate {} opts {:bs-class "button-toolbar"})] 75 | (d/div {:role "toolbar" 76 | :class (d/class-set (t/bs-class-set bs))} 77 | children))) 78 | 79 | ;; ## Button Group 80 | 81 | (s/defn button-group :- t/Component 82 | "Renders the supplied children in a wrapping button-group div." 83 | [opts :- ButtonGroup & children] 84 | (let [[bs props] (t/separate ButtonGroup opts {:bs-class "button-group"}) 85 | classes (merge (t/bs-class-set bs) 86 | {:btn-group (not (:vertical? bs)) 87 | :btn-group-vertical (:vertical? bs) 88 | :btn-group-justified (:justified? bs)})] 89 | (d/div (u/merge-props props {:class (d/class-set classes)}) 90 | children))) 91 | 92 | ;; ## Dropdown Button 93 | 94 | (def DropdownButton 95 | (t/bootstrap 96 | {(s/optional-key :title) t/Renderable 97 | (s/optional-key :href) s/Str 98 | (s/optional-key :on-click) (s/=> s/Any s/Any) 99 | (s/optional-key :on-select) (s/=> s/Any s/Any) 100 | (s/optional-key :pull-right?) s/Bool 101 | (s/optional-key :dropup?) s/Bool 102 | (s/optional-key :nav-item?) s/Bool})) 103 | 104 | (defn render-nav-item [props open? children] 105 | (let [classes {:dropdown true 106 | :open open? 107 | :dropup (:dropup? props)}] 108 | (d/li {:class (d/class-set classes)} 109 | children))) 110 | 111 | (defn render-button-group [props open? children] 112 | (let [group-classes {:open open? 113 | :dropup (:dropup? props)}] 114 | (button-group {:bs-size (:bs-size props) 115 | :class (d/class-set group-classes)} 116 | children))) 117 | 118 | ;; ## Dropdown Button 119 | 120 | (def MenuItem 121 | (t/bootstrap 122 | {:key s/Str 123 | (s/optional-key :header?) s/Bool 124 | (s/optional-key :divider?) s/Bool 125 | (s/optional-key :href) s/Str 126 | (s/optional-key :title) s/Str 127 | (s/optional-key :on-select) (s/=> s/Any s/Any)})) 128 | 129 | (defcomponentk menu-item* 130 | "Generates an Om component of a menu item. Done this way so that 131 | wrapping dropdowns will have access to the Om state." 132 | [owner] 133 | (render 134 | [_] 135 | (let [{:keys [opts children]} (om/get-props owner) 136 | [bs props] (t/separate MenuItem opts {:href "#"}) 137 | classes {:dropdown-header (:header? bs) 138 | :divider (:divider? bs)} 139 | handle-click (fn [e] 140 | (when-let [on-select (:on-select bs)] 141 | (.preventDefault e) 142 | (on-select (:key bs)))) 143 | children (if (:header? bs) 144 | children 145 | (d/a {:on-click handle-click 146 | :href (:href bs) 147 | :title (:title bs) 148 | :tab-index "-1"} 149 | children)) 150 | li-attrs (merge {:role "presentation" 151 | :class (d/class-set classes)} 152 | (when-let [k (:key bs)] 153 | {:key k}))] 154 | (d/li (u/merge-props props li-attrs) 155 | children)))) 156 | 157 | (s/defn menu-item :- t/Component 158 | [opts :- MenuItem & children] 159 | (->menu-item* {:opts opts 160 | :children children})) 161 | 162 | (def DropdownMenu 163 | (t/bootstrap 164 | {(s/optional-key :pull-right?) s/Bool 165 | (s/optional-key :on-select) (s/=> s/Any s/Any)})) 166 | 167 | (s/defn dropdown-menu :- t/Component 168 | [opts :- DropdownMenu & children] 169 | (let [[bs props] (t/separate DropdownMenu opts) 170 | classes {:dropdown-menu true 171 | :dropdown-menu-right (:pull-right? bs)} 172 | ul-attrs {:class (d/class-set classes) 173 | :role "menu"}] 174 | (d/ul (u/merge-props props ul-attrs) 175 | (if-let [on-select (:on-select bs)] 176 | (map #(u/clone-with-props % {:on-select on-select}) children) 177 | children)))) 178 | 179 | (defcomponentk dropdown* 180 | "Generates a dropdown button component responsible for its own 181 | toggled state. The open? toggling is handled through a dropdown 182 | mixin." 183 | [owner state] 184 | (:mixins m/dropdown-mixin) 185 | (render 186 | [_] 187 | (let [open? ((aget owner "isDropdownOpen")) 188 | {:keys [opts children]} (om/get-props owner) 189 | [bs props] (t/separate DropdownButton opts {:href "#"}) 190 | set-dropdown (aget owner "setDropdownState") 191 | render-fn (partial (if (:nav-item? bs) 192 | render-nav-item 193 | render-button-group) 194 | bs open?) 195 | button-props {:ref "dropdownButton" 196 | :class "dropdown-toggle" 197 | :key 0 198 | :nav-dropdown? (:nav-item? bs) 199 | :on-click (fn [e] 200 | (.preventDefault e) 201 | (set-dropdown (not open?)))} 202 | update-child-props (fn [props] 203 | (let [handle 204 | (when (or (:on-select (:opts props)) 205 | (:on-select bs)) 206 | (fn [key] 207 | (if-let [os (:on-select bs)] 208 | (os key) 209 | (set-dropdown false))))] 210 | (update-in props [:opts] 211 | u/merge-props 212 | {:on-select handle})))] 213 | (render-fn 214 | [(button 215 | (u/merge-props (dissoc opts :nav-item? :title :pull-right? :dropup?) 216 | button-props) 217 | (:title bs) " " (d/span {:class "caret"})) 218 | (dropdown-menu 219 | {:ref "menu" 220 | :aria-labelledby (:id props) 221 | :pull-right? (:pull-right? bs) 222 | :key 1} 223 | (map #(u/clone-with-props % update-child-props) children))])))) 224 | 225 | (s/defn dropdown :- t/Component 226 | "Returns a dropdown button component. The component manages its own 227 | dropdown state." 228 | [opts :- DropdownButton & children] 229 | (->dropdown* {:opts opts 230 | :children children})) 231 | 232 | ;; ## Split Button 233 | 234 | (def SplitButton 235 | (t/bootstrap 236 | {(s/optional-key :pull-right?) s/Bool 237 | (s/optional-key :dropup?) s/Bool 238 | (s/optional-key :disabled?) s/Bool 239 | (s/optional-key :title) t/Renderable 240 | (s/optional-key :href) s/Str 241 | (s/optional-key :dropdown-title) t/Renderable 242 | (s/optional-key :on-click) (s/=> s/Any s/Any) 243 | (s/optional-key :on-select) (s/=> s/Any s/Any)})) 244 | 245 | (defcomponentk split* 246 | "Generates a split button component responsible for its own 247 | toggled state. The open? toggling is handled through a dropdown 248 | mixin." 249 | [owner state] 250 | (:mixins m/dropdown-mixin) 251 | (render 252 | [_] 253 | (let [open? ((aget owner "isDropdownOpen")) 254 | {:keys [opts children]} (om/get-props owner) 255 | [bs props] (t/separate SplitButton opts 256 | {:dropdown-title "Toggle dropdown"}) 257 | set-dropdown (aget owner "setDropdownState") 258 | btn-props (partial u/merge-props (dissoc opts :title :id)) 259 | btn (button (btn-props 260 | {:ref "button" 261 | :on-click (fn [e] 262 | (when open? 263 | (set-dropdown false)) 264 | (when-let [f (:on-click bs)] 265 | (f e)))}) 266 | (:title bs)) 267 | drop-btn (button (btn-props 268 | {:ref "dropdownButton" 269 | :class "dropdown-toggle" 270 | :on-click (fn [e] 271 | (.preventDefault e) 272 | (set-dropdown (not open?)))}) 273 | (d/span {:class "sr-only"} (:dropdown-title bs)) 274 | (d/span {:class "caret"})) 275 | menu (dropdown-menu {:ref "menu" 276 | :aria-labelledby (:id props) 277 | :pull-right? (:pull-right? bs) 278 | :on-select (fn [k] 279 | (when-let [f (:on-select bs)] 280 | (f k)) 281 | (set-dropdown false))} 282 | children)] 283 | (button-group {:bs-size (:bs-size bs) 284 | :id (:id props) 285 | :class (d/class-set 286 | {:open open? 287 | :dropup (:dropup? bs)})} 288 | btn drop-btn menu)))) 289 | 290 | (s/defn split 291 | [opts :- SplitButton & children] 292 | (->split* {:opts opts 293 | :children children})) 294 | -------------------------------------------------------------------------------- /src/om_bootstrap/grid.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.grid 2 | "Grid, Row, Col." 3 | (:require [om-bootstrap.types :as t] 4 | [om-bootstrap.util :as u] 5 | [om-tools.dom :as d :include-macros true] 6 | [schema.core :as s :include-macros true])) 7 | 8 | ;; ## Schema 9 | 10 | (def Grid 11 | (t/bootstrap 12 | {(s/optional-key :fluid?) s/Bool})) 13 | 14 | (def col-keys 15 | #{:xs :sm :md :lg 16 | :xs-offset :sm-offset :md-offset :lg-offset 17 | :xs-push :sm-push :md-push :lg-push 18 | :xs-pull :sm-pull :md-pull :lg-pull}) 19 | 20 | (def Col 21 | (t/bootstrap 22 | (-> (map s/optional-key col-keys) 23 | (zipmap (repeat s/Int))))) 24 | 25 | ;; ## Code 26 | ;; 27 | ;; TODO: Do we want a custom component class, like in react-bootstrap? 28 | (s/defn grid :- t/Component 29 | "Generates a wrapper for a bootstrap grid." 30 | [opts :- Grid & children] 31 | (let [[bs props] (t/separate Grid opts {}) 32 | class (if (:fluid? bs) 33 | "container-fluid" 34 | "container")] 35 | (d/div (u/merge-props props {:class class}) 36 | children))) 37 | 38 | (s/defn row :- t/Component 39 | "Generates a Bootstrap row element." 40 | [opts & children] 41 | (d/div (u/merge-props opts {:class "row"}) 42 | children)) 43 | 44 | (s/defn col :- t/Component 45 | "Generates a Bootstrap column element." 46 | [opts :- Col & children] 47 | (let [[bs props] (t/separate Col opts {}) 48 | class (-> (map (fn [[k v]] 49 | (str "col-" (name k) "-" v)) 50 | (select-keys bs col-keys)) 51 | (zipmap (repeat true)) 52 | (d/class-set))] 53 | (d/div (u/merge-props props {:class class}) 54 | children))) 55 | -------------------------------------------------------------------------------- /src/om_bootstrap/input.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.input 2 | (:require [clojure.string :as string] 3 | [om.core :as om] 4 | [om-bootstrap.types :as t] 5 | [om-bootstrap.util :as u] 6 | [om-tools.dom :as d :include-macros true] 7 | [schema.core :as s :include-macros true])) 8 | 9 | ;; ## Bootstrap Inputs for Om 10 | ;; 11 | ;; The following fields come from converting: 12 | ;; 13 | ;; https://github.com/react-bootstrap/react-bootstrap/blob/master/src/Input.jsx 14 | 15 | ;; React Bootstrap has some good stuff to learn from on how to make 16 | ;; inputs. 17 | ;; 18 | ;; https://github.com/react-bootstrap/react-bootstrap 19 | ;; 20 | ;; 21 | ;; QUESTION: Do we need the :key field here? :ref makes sense, not 22 | ;; sure about :key. 23 | ;; 24 | ;; QUESTION: Should have Input just take children as varargs, instead 25 | ;; of a specific key? 26 | 27 | ;; ### Schema 28 | 29 | (def Addons 30 | {(s/optional-key :addon-before) (s/either s/Str t/Component) 31 | (s/optional-key :addon-after) (s/either s/Str t/Component) 32 | (s/optional-key :addon-button) (s/either s/Str t/Component) 33 | (s/optional-key :addon-button-before) (s/either s/Str t/Component) 34 | (s/optional-key :addon-button-after) (s/either s/Str t/Component)}) 35 | 36 | (def FeedbackIcons 37 | "Helps render feedback icons." 38 | {(s/optional-key :bs-style) (s/enum "success" "warning" "error") 39 | (s/optional-key :feedback?) s/Bool}) 40 | 41 | (def Input 42 | "Input fields that match these bad dawgs: 43 | https://github.com/react-bootstrap/react-bootstrap/blob/master/src/Input.jsx" 44 | (t/bootstrap 45 | (merge Addons 46 | FeedbackIcons 47 | {(s/optional-key :type) s/Str 48 | (s/optional-key :label) s/Str 49 | (s/optional-key :skip-form-group?) (s/named s/Bool "DON'T render a wrapping form group?") 50 | (s/optional-key :help) s/Str 51 | (s/optional-key :group-classname) s/Str 52 | (s/optional-key :wrapper-classname) s/Str 53 | (s/optional-key :label-classname) s/Str}))) 54 | 55 | (def Radio 56 | (t/bootstrap 57 | {:label s/Str 58 | (s/optional-key :checked?) s/Bool 59 | (s/optional-key :inline?) s/Bool})) 60 | 61 | ;; ### Utilities 62 | 63 | (s/defn class-set :- s/Str 64 | "Mimics the class-set behavior from React. Pass in a map of 65 | potential class to Boolean; you'll get back a class string that 66 | represents the final class to apply. 67 | 68 | TODO: Use class-set from om-tools." 69 | [klasses :- {(s/either s/Str s/Keyword) s/Bool}] 70 | (->> (mapcat (fn [[k keep?]] 71 | (when keep? [(name k)])) 72 | klasses) 73 | (string/join " "))) 74 | 75 | (s/defn glyph :- t/Component 76 | "To be used with :addon-before or :addon-after." 77 | [glyph-name :- s/Str] 78 | (d/span {:class (str "glyphicon glyphicon-" glyph-name)})) 79 | 80 | (s/defn render-icon :- t/Component 81 | [{:keys [feedback? bs-style]} :- FeedbackIcons] 82 | (when feedback? 83 | (let [klasses {:glyphicon true 84 | :form-control-feedback true 85 | :glyphicon-ok (= "success" bs-style) 86 | :glyphicon-warning-sign (= "warning" bs-style) 87 | :glyphicon-remove (= "error" bs-style)}] 88 | (d/span {:class (class-set klasses)})))) 89 | 90 | (s/defn render-help 91 | [help :- (s/maybe s/Str)] 92 | (when help 93 | (d/span {:class "help-block"} help))) 94 | 95 | (s/defn render-input-group 96 | "Items is a vector of render instances." 97 | [{:keys [addon-before addon-after addon-button addon-button-before addon-button-after]} :- Addons 98 | items :- s/Any] 99 | (if (or addon-before addon-after addon-button addon-button-before addon-button-after) 100 | (d/div {:class "input-group"} 101 | (when addon-before 102 | (d/span {:class "input-group-addon"} addon-before)) 103 | (when addon-button-before 104 | (d/span {:class "input-group-btn"} addon-button-before)) 105 | items 106 | (when addon-after 107 | (d/span {:class "input-group-addon"} addon-after)) 108 | (when addon-button 109 | (d/span {:class "input-group-btn"} addon-button)) 110 | (when addon-button-after 111 | (d/span {:class "input-group-btn"} addon-button-after))) 112 | items)) 113 | 114 | (s/defn checkbox-or-radio? :- s/Bool 115 | "Returns true if the supplied input is of type checkbox or radio, 116 | false otherwise." 117 | [{type :type} :- Input] 118 | (or (= type "checkbox") 119 | (= type "radio"))) 120 | 121 | (s/defn checkbox-or-radio-wrapper :- t/Component 122 | "Wraps this business in a div." 123 | [{type :type} :- Input 124 | children] 125 | (let [klasses {:checkbox (= "checkbox" type) 126 | :radio (= "radio" type)}] 127 | (d/div {:class (class-set klasses)} 128 | children))) 129 | 130 | (s/defn render-label 131 | "This doesn't handle any control group stuff." 132 | ([input :- Input] (render-label input nil)) 133 | ([{lc :label-classname label :label :as input} :- Input 134 | child] 135 | (let [classes (merge {:control-label (not (checkbox-or-radio? input))} 136 | (when lc {lc (boolean lc)}))] 137 | (if label 138 | (d/label {:class (class-set classes)} 139 | child 140 | label) 141 | child)))) 142 | 143 | (s/defn render-wrapper 144 | [{wc :wrapper-classname} :- Input 145 | child] 146 | (if wc 147 | (d/div {:class wc} child) 148 | child)) 149 | 150 | (s/defn render-form-group :- t/Component 151 | "Wraps the entire form group." 152 | [{bs-style :bs-style cn :group-classname :as input} :- Input 153 | children] 154 | (let [classes (merge {:form-group (not (:skip-form-group? input)) 155 | :has-feedback (boolean (:feedback? input)) 156 | :has-success (= "success" bs-style) 157 | :has-warning (= "warning" bs-style) 158 | :has-error (= "error" bs-style)} 159 | (when cn {cn (boolean cn)}))] 160 | (d/div {:class (class-set classes)} 161 | children))) 162 | 163 | (s/defn render-input :- t/Component 164 | [input :- Input attrs children] 165 | (let [props (fn [klass] 166 | (u/merge-props attrs {:class klass 167 | :ref "input" 168 | :key "input"}))] 169 | (if-not (:type input) 170 | children 171 | (case (:type input) 172 | "select" (d/select (props "form-control") children) 173 | "textarea" (d/textarea (props "form-control")) 174 | "static" (d/p (props "form-control-static") (:value attrs)) 175 | (d/input (assoc (props (if (checkbox-or-radio? input) 176 | "" 177 | "form-control")) 178 | :type (:type input)) 179 | children))))) 180 | 181 | ;; ### API Methods 182 | 183 | (s/defn input :- t/Component 184 | "Returns an input component. This currently does NOT handle any of 185 | the default values or validation messages that we'll need to make 186 | this work, though." 187 | [opts :- Input & children] 188 | (let [[input attrs] (t/separate Input opts)] 189 | (if (checkbox-or-radio? input) 190 | (->> [(->> (render-input input attrs children) 191 | (render-label input) 192 | (checkbox-or-radio-wrapper input)) 193 | (render-help (:help input))] 194 | (render-wrapper input) 195 | (render-form-group input)) 196 | (->> [(render-label input) 197 | (->> [(render-input-group 198 | (select-keys input [:addon-before :addon-after :addon-button :addon-button-before :addon-button-after]) 199 | (render-input input attrs children)) 200 | (render-icon (select-keys input [:feedback? :bs-style])) 201 | (render-help (:help input))] 202 | (render-wrapper input))] 203 | (render-form-group input))))) 204 | 205 | ;; ### Input Candidates 206 | ;; 207 | ;; These bad dawgs need to be abstracted out into more solid input 208 | ;; components. Putting them here for now. 209 | 210 | (s/defn radio-option :- t/Component 211 | "Generates a radio button entry, to place into a radio button 212 | grouping." 213 | [opts :- Radio] 214 | (let [[bs props] (t/separate Radio opts {:ref "input" 215 | :key "input" 216 | :type "radio"}) 217 | {:keys [label checked? inline?]} bs 218 | core (d/input (assoc props :checked checked?))] 219 | (if inline? 220 | (d/label {:class "radio-inline"} core label) 221 | (d/div {:class "radio"} (d/label {} core label))))) 222 | 223 | (s/defn options :- [t/Component] 224 | "Returns a sequence of options for use as the children of a select 225 | input." 226 | [header :- s/Str 227 | opts :- [(s/pair s/Str "option value" 228 | s/Str "option label")]] 229 | (cons (d/option {:value ""} header) 230 | (for [[v label] opts] 231 | (d/option {:value v} label)))) 232 | -------------------------------------------------------------------------------- /src/om_bootstrap/mixins.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.mixins 2 | (:require [cljs.core.async :as a :refer [put!]] 3 | [om.core :as om] 4 | [om-tools.mixin :refer-macros [defmixin]] 5 | [schema.core :as s :include-macros true])) 6 | 7 | ;; ## Listener Mixin 8 | 9 | (s/defn event-listener :- (s/=> s/Any) 10 | "Registers the callback on the supplied target for events of type 11 | `event-type`. Returns a function of no arguments that, when called, 12 | unregisters the callback." 13 | [target :- s/Any 14 | event-type :- s/Str 15 | callback :- (s/=> s/Any s/Any)] 16 | (cond (.-addEventListener target) 17 | (do (.addEventListener target event-type callback false) 18 | (fn [] (.removeEventListener target event-type callback false))) 19 | 20 | (.-attachEvent target) 21 | (let [event-type (str "on" event-type)] 22 | (.attachEvent target event-type callback) 23 | (fn [] (.detachEvent target event-type callback))) 24 | :else (fn []))) 25 | 26 | (defmixin set-listener-mixin 27 | "Handles a sequence of listeners for the component, and removes them 28 | from the document when the component is unmounted." 29 | (will-mount [owner] (set! (.-listeners owner) #js [])) 30 | (will-unmount [owner] (doseq [l (.-listeners owner)] 31 | (l))) 32 | (set-listener [owner target event-type callback] 33 | (let [remove-fn (event-listener target event-type callback)] 34 | (.push (.-listeners owner) remove-fn)))) 35 | 36 | ;; ## Timeout Mixin 37 | 38 | (defmixin set-timeout-mixin 39 | "Handles a sequence of timeouts for the component, and removes them 40 | from the document when the component is unmounted." 41 | (will-mount [owner] (set! (.-timeouts owner) #js [])) 42 | (will-unmount [owner] 43 | (.. owner -timeouts (map #(js/clearTimeout %)))) 44 | (set-timeout [owner f timeout] 45 | (let [timeout (js/setTimeout f timeout)] 46 | (.push (.-timeouts owner) timeout)))) 47 | 48 | ;; ## Dropdown Mixin 49 | 50 | (defn in-root? 51 | "Accepts two DOM elements; returns true if the supplied node is 52 | nested inside the supplied root, false otherwise." 53 | [node root] 54 | (loop [node node] 55 | (cond (nil? node) false 56 | (= root node) true 57 | :else (recur (.-parentNode node))))) 58 | 59 | (def ESCAPE_KEY 27) 60 | 61 | (defn bind-root-close-handlers! 62 | "For dropdowns, binds a handler for that sets the dropdown-mixin's 63 | `:open?` state to false if the user clicks outside the owning 64 | component OR hits the escape key." 65 | [owner] 66 | (let [set-state (aget owner "setDropdownState")] 67 | (set! (.-dropdownListeners owner) 68 | (array 69 | (event-listener 70 | js/document "click" 71 | (fn [e] 72 | (when-not (in-root? (.-target e) (om/get-node owner)) 73 | (set-state false)))) 74 | (event-listener 75 | js/document "keyup" 76 | (fn [e] 77 | (when (= ESCAPE_KEY (.-keyCode e)) 78 | (set-state false)))))))) 79 | 80 | (defn unbind-root-close-handlers! 81 | "If they're present on the owning object, removes the listeners 82 | registered by the dropdown mixin." 83 | [owner] 84 | (when-let [listeners (.-dropdownListeners owner)] 85 | (doseq [l listeners] 86 | (l)) 87 | (set! (.-dropdownListeners owner) nil))) 88 | 89 | (defmixin dropdown-mixin 90 | "Mixin that manages a single piece of state - :open?. If a user 91 | clicks outside the component's owning dom element OR hits the escape 92 | key, the state will jump back to false. 93 | 94 | Down the road this may need to register a callback when the state 95 | changes." 96 | (init-state [_] {:open? false}) 97 | (will-unmount [owner] (unbind-root-close-handlers! owner)) 98 | ;; This function exists because om-tools mixins can't share state 99 | ;; with the component that uses them: 100 | ;; https://github.com/Prismatic/om-tools/issues/28 101 | (isDropdownOpen [owner] (om/get-state owner :open?)) 102 | (setDropdownState 103 | [owner open?] 104 | (if open? 105 | (bind-root-close-handlers! owner) 106 | (unbind-root-close-handlers! owner)) 107 | (om/set-state! owner [:open?] open?))) 108 | 109 | (defmixin collapsible-mixin 110 | "Mixin that enables collapsible Panels. Similar to the Dropdown 111 | Mixin it only manages a single piece of state - :collapsed?. The Panel 112 | is opened and closen by clicking on the header." 113 | (init-state [_] {:collapsed? true}) 114 | (isPanelCollapsed [owner] 115 | (let [collapsed? (om/get-state owner :collapsed?)] 116 | (if (nil? collapsed?) 117 | (do (om/set-state! owner :collapsed? true) 118 | true) 119 | collapsed?))) 120 | (toggleCollapsed 121 | [owner] 122 | (om/update-state! owner [:collapsed?] not))) 123 | -------------------------------------------------------------------------------- /src/om_bootstrap/modal.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.modal 2 | "IN PROGRESS work on a modal component. Depends on a fade mixin." 3 | (:require [om.core :as om] 4 | [om-bootstrap.types :as t] 5 | [om-tools.core :refer-macros [defcomponentk]] 6 | [om-tools.dom :as d :include-macros true] 7 | [schema.core :as s :include-macros true] 8 | [om-bootstrap.util :as u])) 9 | 10 | ;; ## Schema 11 | 12 | (def Modal 13 | "Options for the modal." 14 | {:header s/Any 15 | :footer s/Any 16 | (s/optional-key :keyboard?) s/Bool 17 | (s/optional-key :close-button?) s/Bool 18 | (s/optional-key :visible?) s/Bool 19 | (s/optional-key :animate?) s/Bool}) 20 | 21 | (defcomponentk modal* 22 | "Component that renders a Modal. Manages it's own toggle state" 23 | [owner state] 24 | (init-state [_] 25 | {:visible? (get-in (om/get-props owner) [:opts :visible?])}) 26 | (will-receive-props [this next-props] 27 | (let [last-props (om/get-props owner) 28 | last-visible? (om/get-state owner [:visible?]) 29 | next-visible? (get-in next-props [:opts :visible?])] 30 | (when (not= last-visible? next-visible?) 31 | (om/set-state! owner [:visible?] next-visible?)))) 32 | (render [_] 33 | (let [{:keys [opts children]} (om/get-props owner) 34 | [bs props] (t/separate Modal opts {:bs-class "modal"}) 35 | classes {:modal true 36 | :fade true 37 | :in (om/get-state owner [:visible?])}] 38 | (d/div (u/merge-props props 39 | {:class (d/class-set classes)}) 40 | (d/div {:class "modal-dialog"} 41 | (d/div {:class "modal-content"} 42 | (d/div {:class "modal-header"} 43 | (when (:close-button? bs) 44 | (d/button {:type "button" 45 | :class "close" 46 | :aria-hidden true 47 | :on-click (fn [_] (om/set-state! owner [:visible?] false))} 48 | "×")) 49 | (u/clone-with-props (:header bs) {:class "modal-title"})) 50 | (d/div {:class "modal-body"} 51 | children) 52 | (d/div {:class "modal-footer"} 53 | (:footer bs)))))))) 54 | 55 | (s/defn modal 56 | [opts :- Modal & children] 57 | (->modal* {:opts opts :children children})) 58 | -------------------------------------------------------------------------------- /src/om_bootstrap/nav.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.nav 2 | (:require [clojure.string :as st] 3 | [om.core :as om] 4 | [om-bootstrap.types :as t] 5 | [om-bootstrap.util :as u] 6 | [om-tools.core :refer-macros [defcomponentk]] 7 | [om-tools.dom :as d :include-macros true] 8 | [schema.core :as s :include-macros true])) 9 | 10 | ;; ## NavItem 11 | 12 | (def NavItem 13 | (t/bootstrap 14 | {(s/optional-key :title) s/Str 15 | (s/optional-key :on-select) (s/=> s/Any s/Any) 16 | (s/optional-key :active?) s/Bool 17 | (s/optional-key :disabled?) s/Bool 18 | (s/optional-key :href) s/Str})) 19 | 20 | (defcomponentk nav-item* 21 | "Generates a nav item for use inside of a nav element." 22 | [owner] 23 | (render 24 | [_] 25 | (let [{:keys [opts children]} (om/get-props owner) 26 | [bs props] (t/separate NavItem opts {:href "#"}) 27 | classes {:active (:active? bs) 28 | :disabled (:disabled? bs)} 29 | handle-click (fn [e] 30 | (when-let [f (:on-select bs)] 31 | (.preventDefault e) 32 | (when-not (:disabled? bs) 33 | (f (:key props) 34 | (:href bs)))))] 35 | (d/li (u/merge-props props {:class (d/class-set classes)}) 36 | (d/a {:href (:href bs) 37 | :ref "anchor" 38 | :title (:title bs) 39 | :on-click handle-click} 40 | children))))) 41 | 42 | (s/defn nav-item :- t/Component 43 | [opts :- NavItem & children] 44 | (->nav-item* {:opts opts 45 | :children children})) 46 | 47 | ;; ## Nav 48 | 49 | (def Nav 50 | (t/bootstrap 51 | {:bs-style (s/enum "tabs" "pills") 52 | (s/optional-key :active-key) (s/either s/Str s/Num) 53 | (s/optional-key :active-href) s/Str 54 | (s/optional-key :stacked?) s/Bool 55 | (s/optional-key :justified?) s/Bool 56 | (s/optional-key :collapsible?) s/Bool 57 | (s/optional-key :expanded?) s/Bool 58 | (s/optional-key :navbar?) s/Bool 59 | (s/optional-key :pull-right?) s/Bool})) 60 | 61 | (s/defn child-active? :- s/Bool 62 | "Accepts a NavItem's child props and the current options provided to 63 | the Nav bar; returns true if the child component should be active, 64 | false otherwise." 65 | [child-props opts] 66 | (boolean 67 | (or (:active? child-props) 68 | (when-let [ak (:active-key opts)] 69 | (= ak (:key child-props))) 70 | (when-let [ak (:active-href opts)] 71 | (= ak (:href child-props)))))) 72 | 73 | (s/defn clone-nav-item 74 | "Takes the options supplied to the top level nav and returns a 75 | function that will CLONE the inner nav items, transferring all 76 | relevant props from the outer code to the inner code." 77 | [opts] 78 | (letfn [(prop-fn [props] 79 | (let [base (-> (select-keys opts [:on-select :active-key :active-href]) 80 | (assoc :active? (child-active? (:opts props) opts) 81 | :nav-item? true))] 82 | (update-in props [:opts] u/merge-props base)))] 83 | (fn [child] 84 | (u/clone-with-props child prop-fn)))) 85 | 86 | (defcomponentk nav* [owner] 87 | (render 88 | [_] 89 | (let [{:keys [opts children]} (om/get-props owner) 90 | [bs props] (t/separate Nav opts {:expanded? true 91 | :bs-class "nav"}) 92 | classes {:navbar-collapse (:collapsible? bs) 93 | :collapse (not (:expanded? bs)) 94 | :in (:expanded? bs)}] 95 | (if (and (:navbar? bs) 96 | (not (:collapsible? bs))) 97 | (let [children (map (clone-nav-item opts) children) 98 | ul-props {:ref "ul" 99 | :class (d/class-set 100 | (merge (t/bs-class-set bs) 101 | {:nav-stacked (:stacked? bs) 102 | :nav-justified (:justified? bs) 103 | :navbar-nav (:navbar? bs) 104 | :pull-right (:pull-right? bs)}))}] 105 | (d/ul (u/merge-props props ul-props) children)) 106 | (let [ul-props-left {:ref "ul" 107 | :class (d/class-set 108 | (merge (t/bs-class-set bs) 109 | {:nav-stacked (:stacked? bs) 110 | :nav-justified (:justified? bs) 111 | :navbar-nav (:navbar? bs) 112 | :pull-right false}))} 113 | ul-props-right 114 | {:ref "ul" 115 | :class (d/class-set 116 | (merge (t/bs-class-set bs) 117 | {:nav-stacked (:stacked? bs) 118 | :nav-justified (:justified? bs) 119 | :navbar-nav (:navbar? bs) 120 | :pull-right true}))} 121 | [children-left _ children-right] (partition-by #(= :right %) children) 122 | children-left (map (clone-nav-item opts) children-left) 123 | children-right (map (clone-nav-item opts) children-right)] 124 | (d/nav (u/merge-props props {:class (d/class-set classes)}) 125 | (if (not (empty? children-left)) (d/ul ul-props-left children-left)) 126 | (if (not (empty? children-right))(d/ul ul-props-right children-right)))))))) 127 | 128 | (s/defn nav :- t/Component 129 | [opts :- Nav & children] 130 | (->nav* {:opts opts 131 | :children children})) 132 | 133 | ;; ## SubNav 134 | 135 | 136 | ;; ## NavBar 137 | 138 | (def NavBar 139 | (t/bootstrap 140 | {(s/optional-key :component-fn) (s/=> s/Any s/Any) 141 | (s/optional-key :fixed-top?) s/Bool 142 | (s/optional-key :fixed-bottom?) s/Bool 143 | (s/optional-key :static-top?) s/Bool 144 | (s/optional-key :inverse?) s/Bool 145 | (s/optional-key :role) s/Str 146 | (s/optional-key :brand) t/Renderable 147 | (s/optional-key :on-toggle) (s/=> s/Any s/Any) 148 | (s/optional-key :toggle-nav-key) s/Str 149 | (s/optional-key :nav-expanded?) s/Bool 150 | (s/optional-key :default-nav-expanded?) s/Bool})) 151 | 152 | (defn render-toggle-button [owner bs] 153 | (let [handle-toggle (fn [] 154 | (when-let [f (:on-toggle bs)] 155 | (om/set-state-nr! owner [:changing?] true) 156 | (f) 157 | (om/set-state-nr! owner [:changing?] false)) 158 | (om/update-state! owner [:nav-open?] not)) 159 | tb (u/clone-with-props (:toggle-button bs) 160 | {:class "navbar-toggle" 161 | :on-click handle-toggle})] 162 | (d/button {:class "navbar-toggle" 163 | :type "button" 164 | :on-click handle-toggle} 165 | (or tb [(d/span {:class "sr-only" :key 0} "Toggle navigation") 166 | (d/span {:class "icon-bar" :key 1}) 167 | (d/span {:class "icon-bar" :key 2}) 168 | (d/span {:class "icon-bar" :key 3})])))) 169 | 170 | (s/defn render-header-and-toggle-btn? :- s/Bool 171 | "Returns true if any of the necessary properties are in place to 172 | render the navbar-header and toggle button." 173 | [bs] 174 | (boolean 175 | (or (:brand bs) 176 | (:toggle-button bs) 177 | (:toggle-nav-key bs)))) 178 | 179 | (defn render-header [owner bs] 180 | (d/div {:class "navbar-header"} 181 | (if (u/strict-valid-component? (:brand bs)) 182 | (u/clone-with-props (:brand bs) {:class "navbar-brand"}) 183 | (d/span {:class "navbar-brand"} (:brand bs))) 184 | (when (render-header-and-toggle-btn? bs) 185 | (render-toggle-button owner bs)))) 186 | 187 | (defn render-navbar-child [owner child bs] 188 | (let [f (fn [props] 189 | (let [opts (:opts props) 190 | collapsible? (or (:collapsible? opts) 191 | (when (:toggle-nav-key bs) 192 | (= (:key opts) (:toggle-nav-key bs)))) 193 | base {:navbar? true 194 | :collapsible? collapsible? 195 | :expanded? (and collapsible? 196 | (or (:nav-expanded? bs) 197 | (om/get-state owner :nav-open?)))}] 198 | (update-in props [:opts] u/merge-props base)))] 199 | (u/clone-with-props child f))) 200 | 201 | (defcomponentk navbar* 202 | [[:data opts children] owner] 203 | (init-state [_] {:nav-open? (:default-nav-expanded? opts) 204 | :changing? false}) 205 | (should-update [_ _ next-state] 206 | (not (:changing? next-state))) 207 | (render 208 | [_] 209 | (let [[bs props] (t/separate NavBar opts 210 | {:bs-class "navbar" 211 | :bs-style "default" 212 | :role "navigation" 213 | :component-fn (fn [opts & c] 214 | (d/nav opts c))}) 215 | classes (assoc (t/bs-class-set bs) 216 | :navbar-fixed-top (:fixed-top? bs) 217 | :navbar-fixed-bottom (:fixed-bottom? bs) 218 | :navbar-static-top (:static-top? bs) 219 | :navbar-inverse (:inverse? bs))] 220 | ((:component-fn bs) (u/merge-props (merge bs props) 221 | {:class (d/class-set classes)}) 222 | (d/div {:class (if (:fluid props) "container-fluid" "container")} 223 | (when (render-header-and-toggle-btn? bs) 224 | (render-header owner bs)) 225 | (map #(render-navbar-child owner % bs) children)))))) 226 | 227 | (s/defn navbar 228 | [opts :- NavBar & children] 229 | (->navbar* {:opts opts 230 | :children children})) 231 | -------------------------------------------------------------------------------- /src/om_bootstrap/pagination.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.pagination 2 | (:refer-clojure :exclude [next]) 3 | (:require [om.core :as om] 4 | [om-bootstrap.types :as t] 5 | [om-bootstrap.util :as u] 6 | [om-tools.dom :as d :include-macros true] 7 | [schema.core :as s :include-macros true])) 8 | 9 | (def Page 10 | (t/bootstrap 11 | {(s/optional-key :disabled?) s/Bool 12 | (s/optional-key :active?) s/Bool 13 | (s/optional-key :href) s/Str 14 | (s/optional-key :on-click) (s/=> s/Any s/Any)})) 15 | 16 | (s/defn page :- t/Component [opts :- Page & children] 17 | (let [[bs props] (t/separate Page opts {:href "#"}) 18 | classes {:disabled (:disabled? bs) 19 | :active (:active? bs)}] 20 | (d/li (u/merge-props props {:class (d/class-set classes)}) 21 | (d/a {:href (:href bs) 22 | :on-click (:on-click bs)} 23 | children)))) 24 | 25 | (s/defn previous :- t/Component [opts :- Page] 26 | (page (assoc opts :aria-label "Previous") (d/span {:aria-hidden "true"} "«"))) 27 | 28 | (s/defn next :- t/Component [opts :- Page] 29 | (page (assoc opts :aria-label "Next") (d/span {:aria-hidden "true"} "»"))) 30 | 31 | (s/defn pagination :- t/Component [opts & children] 32 | (d/nav opts 33 | (d/ul {:class "pagination"} 34 | children))) 35 | -------------------------------------------------------------------------------- /src/om_bootstrap/panel.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.panel 2 | (:require [om.core :as om] 3 | [om-bootstrap.mixins :as m] 4 | [om-bootstrap.types :as t] 5 | [om-bootstrap.util :as u] 6 | [om-tools.core :refer-macros [defcomponentk]] 7 | [om-tools.dom :as d :include-macros true] 8 | [schema.core :as s :include-macros true])) 9 | 10 | ;; TODO: Dropdown functionality is NOT there yet, so :on-select is 11 | ;; ignored (https://github.com/racehub/om-bootstrap/issues/17) 12 | 13 | (def Panel 14 | (t/bootstrap 15 | {(s/optional-key :on-select) (s/=> s/Any s/Any) 16 | (s/optional-key :header) t/Renderable 17 | (s/optional-key :footer) t/Renderable 18 | (s/optional-key :list-group) t/Renderable 19 | (s/optional-key :collapsible?) s/Bool 20 | (s/optional-key :collapsed?) s/Bool})) 21 | 22 | (declare ->collapsible-panel*) 23 | 24 | (s/defn panel :- t/Component 25 | [opts :- Panel & children] 26 | (let [[bs props] (t/separate Panel opts {:bs-class "panel" 27 | :bs-style "default"}) 28 | classes (assoc (t/bs-class-set bs) :panel true)] 29 | (if (:collapsible? bs) 30 | (->collapsible-panel* {:opts (dissoc opts :collapsible?) 31 | :children children}) 32 | (d/div (u/merge-props props {:class (d/class-set classes)}) 33 | (when-let [header (:header bs)] 34 | (d/div {:class "panel-heading"} 35 | (u/clone-with-props header {:class "panel-title"}))) 36 | (when-not (= 0 (count (filter identity children))) 37 | (d/div {:class (str "panel-body" (when (:collapsed? bs) " collapse")) 38 | :ref "body"} 39 | children)) 40 | (when-let [list-group (:list-group bs)] 41 | list-group) 42 | (when-let [footer (:footer bs)] 43 | (d/div {:class "panel-footer"} footer)))))) 44 | 45 | ;; ## Collapsible Panel 46 | 47 | (defcomponentk collapsible-panel* 48 | "Generates a collapsible panel component resposible for its own toggled state. 49 | The :collapsed? state is handled through a collapsible mixin." 50 | [owner state] 51 | (:mixins m/collapsible-mixin) 52 | (render [_] 53 | (let [{:keys [opts children]} (om/get-props owner) 54 | is-collapsed? ((aget owner "isPanelCollapsed") owner) 55 | toggle! (fn [_] ((aget owner "toggleCollapsed") owner) false) 56 | collapsible-header (d/h4 57 | (d/a {:href "#" 58 | :on-click toggle!} 59 | (:header opts)))] 60 | (panel (u/merge-props opts {:header collapsible-header 61 | :collapsed? is-collapsed?}) 62 | children)))) 63 | -------------------------------------------------------------------------------- /src/om_bootstrap/progress_bar.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.progress-bar 2 | "IN PROGRESS! (Yuk yuk.) This code is a start, but currently doesn't 3 | work." 4 | (:require [om-bootstrap.types :as t] 5 | [om-tools.dom :as d :include-macros true] 6 | [om-bootstrap.util :as u] 7 | [schema.core :as s :include-macros true])) 8 | 9 | ;; ## Schema 10 | 11 | (def ProgressBar 12 | (t/bootstrap 13 | {:now s/Int 14 | (s/optional-key :min) s/Int 15 | (s/optional-key :max) s/Int 16 | (s/optional-key :label) t/Renderable 17 | (s/optional-key :sr-only?) (s/named s/Bool "Screenreader-only? Hide the label?") 18 | (s/optional-key :striped?) s/Bool 19 | (s/optional-key :active?) s/Bool 20 | (s/optional-key :nested?) (s/named s/Bool "Specify this for a nested ProgressBar inside a stacked ProgressBar.")})) 21 | 22 | (def defaults 23 | {:min 0 24 | :max 100 25 | :bs-class "progress-bar" 26 | :striped? false 27 | :active? false 28 | :nested? false}) 29 | 30 | (s/defn percentage :- s/Num 31 | [min :- s/Int now :- s/Int max :- s/Int] 32 | (-> (/ (- now min) 33 | (- max min)) 34 | (* 100) 35 | (Math/ceil))) 36 | 37 | (s/defn child-bar :- t/Component 38 | "Generates a progress bar child." 39 | [opts :- ProgressBar & children] 40 | (let [[bs props] (t/separate ProgressBar opts defaults) 41 | classes (merge 42 | (t/bs-class-set bs) 43 | {:progress-bar true} 44 | (when (:active? bs) {:progress-bar-striped true 45 | :active true}) 46 | (when (:striped? bs) {:progress-bar-striped true})) 47 | values {:aria-value-min (:min bs) 48 | :aria-value-max (:max bs) 49 | :aria-value-now (:now bs)} 50 | style {:width (str (percentage (:min bs) (:now bs) (:max bs)) "%")}] 51 | (d/div (u/merge-props props 52 | {:class (d/class-set classes)} 53 | values 54 | {:style style}) 55 | (when-let [label (:label bs)] 56 | (if (:sr-only? bs) 57 | (d/span {:class "sr-only"} label) 58 | label))))) 59 | 60 | (s/defn progress-bar 61 | "Generates a progress bar component." 62 | [opts :- ProgressBar & children] 63 | (if (:nested? opts) 64 | (child-bar opts children) 65 | (d/div {:class "progress"} 66 | (child-bar opts children) 67 | children))) 68 | -------------------------------------------------------------------------------- /src/om_bootstrap/random.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.random 2 | "Components that need to be filed, still." 3 | (:require [om.core :as om] 4 | [om-bootstrap.mixins :as m] 5 | [om-bootstrap.types :as t] 6 | [om-bootstrap.util :as u] 7 | [om-tools.core :refer-macros [defcomponentk]] 8 | [om-tools.dom :as d :include-macros true] 9 | [schema.core :as s :include-macros true])) 10 | 11 | ;; ## Jumbotron 12 | 13 | (s/defn jumbotron :- t/Component 14 | "A lightweight, flexible component that can optionally extend the 15 | entire viewport to showcase key content on your site." 16 | [opts & children] 17 | (d/div (u/merge-props opts {:class "jumbotron"}) 18 | children)) 19 | 20 | ;; ## Label 21 | 22 | (s/defn label :- t/Component 23 | "Create a (label {} \"label!\") to show highlight information." 24 | [opts & children] 25 | (let [[bs props] (t/separate {} opts {:bs-class "label" 26 | :bs-style "default"}) 27 | classes (t/bs-class-set bs)] 28 | (d/span (u/merge-props props {:class (d/class-set classes)}) 29 | children))) 30 | 31 | ;; ## Well 32 | 33 | (s/defn well :- t/Component 34 | "Use the well as a simple effect on an element to give it an inset effect." 35 | [opts & children] 36 | (let [[bs props] (t/separate {} opts {:bs-class "well"}) 37 | class (d/class-set (t/bs-class-set bs))] 38 | (d/div (u/merge-props props {:class class}) 39 | children))) 40 | 41 | ;; ## Header 42 | 43 | (s/defn page-header :- t/Component 44 | "A simple shell for an h1 to appropriately space out and segment 45 | sections of content on a page. It can utilize the h1’s default small 46 | element, as well as most other components (with additional styles)." 47 | [opts & children] 48 | (d/div (u/merge-props opts {:class "page-header"}) 49 | (d/h1 children))) 50 | 51 | ;; ## Tooltip 52 | 53 | (def Placement 54 | (s/enum "top" "right" "bottom" "left")) 55 | 56 | (def ToolTip 57 | (t/bootstrap 58 | {(s/optional-key :placement) Placement 59 | (s/optional-key :position-left) s/Int 60 | (s/optional-key :position-top) s/Int 61 | (s/optional-key :arrow-offset-left) s/Int 62 | (s/optional-key :arrow-offset-top) s/Int})) 63 | 64 | (s/defn tooltip :- t/Component 65 | [opts :- ToolTip & children] 66 | (let [[bs _] (t/separate ToolTip opts {:placement "right"}) 67 | classes {:tooltip true 68 | (:placement bs) true 69 | :in (or (:position-left bs) 70 | (:position-top bs))}] 71 | (d/div {:class (d/class-set classes) 72 | :style {:left (:position-left bs) 73 | :top (:position-top bs)}} 74 | (d/div {:class "tooltip-arrow" 75 | :style {:left (:arrow-offset-left bs) 76 | :top (:arrow-offset-top bs)}}) 77 | (d/div {:class "tooltip-inner"} 78 | children)))) 79 | 80 | ;; ## Alert 81 | 82 | (def Alert 83 | (t/bootstrap 84 | {(s/optional-key :on-dismiss) (s/=> s/Any s/Any) 85 | (s/optional-key :dismiss-after) s/Int})) 86 | 87 | (def alert-defaults 88 | {:bs-class "alert" :bs-style "info"}) 89 | 90 | (defcomponentk alert* 91 | "Renders the alert component with timeout mixed in. TODO: This 92 | should probably use the component macro and be defined inline under 93 | the alert function. No need for a separate name." 94 | [[:data bs props children] owner] 95 | (:mixins m/set-timeout-mixin) 96 | (did-mount [_] (when (and (:on-dismiss bs) (:dismiss-after bs)) 97 | (doto owner 98 | (.set-timeout (:on-dismiss bs) 99 | (:dismiss-after bs))))) 100 | (render 101 | [_] 102 | (let [classes (t/bs-class-set bs) 103 | dismiss-button (when-let [od (:on-dismiss bs)] 104 | (d/button {:type "button" 105 | :class "close" 106 | :on-click od 107 | :aria-hidden true} 108 | "×"))] 109 | (d/div (u/merge-props props {:class (d/class-set classes)}) 110 | dismiss-button 111 | children)))) 112 | 113 | (s/defn alert :- t/Component 114 | "Wrapper for the alert component to allow a better user interface." 115 | [opts :- Alert & children] 116 | (let [[bs props] (t/separate Alert opts alert-defaults)] 117 | (om/build alert* {:bs bs 118 | :props props 119 | :children children}))) 120 | 121 | ;; ## Popover 122 | 123 | (def Popover 124 | (t/bootstrap 125 | {(s/optional-key :title) t/Renderable 126 | (s/optional-key :placement) Placement 127 | (s/optional-key :position-left) s/Int 128 | (s/optional-key :position-top) s/Int 129 | (s/optional-key :arrow-offset-left) s/Int 130 | (s/optional-key :arrow-offset-top) s/Int})) 131 | 132 | ;; TODO: Abstract out shared style generation between here and 133 | ;; tooltip. 134 | (s/defn popover :- t/Component 135 | [opts :- Popover & children] 136 | (let [[bs _] (t/separate Popover opts {:placement "right"}) 137 | classes {:popover true 138 | (:placement bs) true 139 | :in (or (:position-left bs) 140 | (:position-top bs))}] 141 | (d/div {:class (d/class-set classes) 142 | :style {:left (:position-left bs) 143 | :top (:position-top bs) 144 | :display "block"}} 145 | (d/div {:class "arrow" 146 | :style {:left (:arrow-offset-left bs) 147 | :top (:arrow-offset-top bs)}}) 148 | (when-let [title (:title bs)] 149 | (d/h3 {:class "popover-title"} title)) 150 | (d/div {:class "popover-content"} 151 | children)))) 152 | 153 | ;; ## Badge 154 | 155 | (def Badge 156 | (t/bootstrap 157 | {(s/optional-key :pull-right?) s/Bool})) 158 | 159 | (s/defn badge :- t/Component 160 | [opts :- Badge & children] 161 | (let [[bs props] (t/separate Badge opts) 162 | classes {:pull-right (:pull-right? bs) 163 | :badge (u/some-valid-component? children)}] 164 | (d/span (u/merge-props props {:class (d/class-set classes)}) 165 | children))) 166 | 167 | ;; ## Glyphicon 168 | 169 | (def Glyphicon 170 | (t/bootstrap {:glyph s/Str})) 171 | 172 | (s/defn glyphicon :- t/Component 173 | [opts :- Glyphicon & children] 174 | (let [[bs props] (t/separate Glyphicon opts {:bs-class "glyphicon"}) 175 | classes (assoc (t/bs-class-set bs) 176 | (str "glyphicon-" (:glyph bs)) true)] 177 | (d/span (u/merge-props props {:class (d/class-set classes)}) 178 | children))) 179 | -------------------------------------------------------------------------------- /src/om_bootstrap/table.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.table 2 | (:require [om.core :as om] 3 | [om-bootstrap.types :as t] 4 | [om-bootstrap.util :as u] 5 | [om-tools.dom :as d :include-macros true] 6 | [schema.core :as s :include-macros true])) 7 | 8 | (def Table 9 | {(s/optional-key :striped?) s/Bool 10 | (s/optional-key :bordered?) s/Bool 11 | (s/optional-key :condensed?) s/Bool 12 | (s/optional-key :hover?) s/Bool 13 | (s/optional-key :responsive?) s/Bool}) 14 | 15 | (s/defn table 16 | "Generates a Bootstrap table wrapper." 17 | [opts :- Table & children] 18 | (let [[bs props] (t/separate Table opts) 19 | klasses {:table true 20 | :table-striped (:striped? opts) 21 | :table-bordered (:bordered? opts) 22 | :table-condensed (:condensed? opts) 23 | :table-hover (:hover? opts)} 24 | props (u/merge-props props {:class (d/class-set klasses)}) 25 | table (d/table props children)] 26 | (if (:responsive? opts) 27 | (d/div {:class "table-responsive"} table) 28 | table))) 29 | -------------------------------------------------------------------------------- /src/om_bootstrap/types.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.types 2 | "Types for working with Bootstrap." 3 | (:require [schema.core :as s :include-macros true])) 4 | 5 | ;; ## Schema Utilities 6 | 7 | (s/defn schema-keys 8 | "Returns all keys from a schema." 9 | [schema :- {s/Any s/Any}] 10 | (map (fn [k] 11 | (if (s/optional-key? k) (:k k) k)) 12 | (keys schema))) 13 | 14 | (s/defn at-least 15 | "Returns a map schema that accepts the supplied map schema, plus any 16 | other optional keys that show up in the map. Such a schema can only 17 | enforce that required keys are missing." 18 | [schema] 19 | (assoc schema s/Any s/Any)) 20 | 21 | ;; ## Schema 22 | 23 | (def Component 24 | (s/named s/Any "Alias for an om component, since I don't know what type to put here.")) 25 | 26 | (def Renderable 27 | (s/named s/Any "Anything that can get rendered.")) 28 | 29 | (def class-map 30 | "Map of keyword to the proper bootstrap class name." 31 | {"alert" "alert" 32 | "button" "btn" 33 | "button-group" "btn-group" 34 | "button-toolbar" "btn-toolbar" 35 | "column" "col" 36 | "input-group" "input-group" 37 | "form" "form" 38 | "glyphicon" "glyphicon" 39 | "label" "label" 40 | "panel" "panel" 41 | "panel-group" "panel-group" 42 | "progress-bar" "progress-bar" 43 | "nav" "nav" 44 | "navbar" "navbar" 45 | "modal" "modal" 46 | "row" "row" 47 | "well" "well"}) 48 | 49 | (def style-map 50 | "Map of style keywords -> styles." 51 | {"default" "default" 52 | "primary" "primary" 53 | "success" "success" 54 | "info" "info" 55 | "warning" "warning" 56 | "danger" "danger" 57 | "link" "link" 58 | "inline" "inline" 59 | "tabs" "tabs" 60 | "pills" "pills"}) 61 | 62 | (def size-map 63 | {"large" "lg" 64 | "medium" "md" 65 | "small" "sm" 66 | "xsmall" "xs"}) 67 | 68 | (def BSClass (apply s/enum (keys class-map))) 69 | (def BSStyle (apply s/enum (keys style-map))) 70 | (def BSSize (apply s/enum (keys size-map))) 71 | 72 | (def BootstrapClass 73 | {(s/optional-key :bs-class) BSClass 74 | (s/optional-key :bs-style) BSStyle 75 | (s/optional-key :bs-size) BSSize}) 76 | 77 | (defn bootstrap 78 | "Applies all default bootstrap options to the supplied schema. If 79 | the incoming schema has one of the the keys from BootstrapClass, 80 | that wins (even if it's required)." 81 | [schema] 82 | (let [bootstrap-schema (->> (select-keys schema [:bs-class :bs-style :bs-size]) 83 | (keys) 84 | (map s/optional-key) 85 | (apply dissoc BootstrapClass))] 86 | (at-least 87 | (merge bootstrap-schema schema)))) 88 | 89 | ;; ## Public API 90 | ;; 91 | ;; Separate follows the best practices set out here: 92 | ;; https://gist.github.com/sebmarkbage/a6e220b7097eb3c79ab7 93 | 94 | (s/defn separate :- (s/pair 95 | {s/Any s/Any} "om-bootstrap options." 96 | {s/Any s/Any} "all other props.") 97 | "Returns two maps; the first is all of the schema options, the 98 | second is the REST of the options." 99 | ([schema opts] 100 | (separate schema opts {})) 101 | ([schema opts defaults] 102 | (let [ks (set (schema-keys (bootstrap schema))) 103 | opts (merge defaults opts)] 104 | [(into {} (filter (comp ks key) opts)) 105 | (into {} (remove (comp ks key) opts))]))) 106 | 107 | (s/defn bs-class-set :- {s/Str s/Bool} 108 | "Returns input for class-set." 109 | [{:keys [bs-class bs-style bs-size]} :- (at-least BootstrapClass)] 110 | (if-let [klass (class-map bs-class)] 111 | (let [prefix (str (name klass) "-")] 112 | (merge {klass true} 113 | (when-let [size (size-map bs-size)] 114 | {(str prefix (name size)) true}) 115 | (when-let [style (style-map bs-style)] 116 | {(str prefix (name style)) true}))) 117 | {})) 118 | -------------------------------------------------------------------------------- /src/om_bootstrap/util.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.util 2 | "Utilities for the om-bootstrap library." 3 | (:require [goog.object :as gobject] 4 | [om.core :as om] 5 | [schema.core :as s :include-macros true])) 6 | 7 | (defn merge-with-fns 8 | "Returns a map that consists of the rest of the maps conj-ed onto 9 | the first. If a key occurs in more than one map, the mapping(s) 10 | from the latter (left-to-right) will be combined with the mapping in 11 | the result by looking up the proper merge function and in the 12 | supplied map of key -> merge-fn and using that for the big merge. If 13 | a key doesn't have a merge function, the right value wins (as with 14 | merge)." 15 | [k->fn maps] 16 | (letfn [(merge-entry [m e] 17 | (let [k (key e) v (val e)] 18 | (if-let [f (and (contains? m k) 19 | (k->fn k))] 20 | (assoc m k (f (get m k) v)) 21 | (assoc m k v)))) 22 | (merge [m1 m2] 23 | (reduce merge-entry (or m1 {}) (seq m2)))] 24 | (reduce merge {} maps))) 25 | 26 | (s/defn collectify :- [s/Any] 27 | [x :- s/Any] 28 | (if (sequential? x) x [x])) 29 | 30 | ;; ## Reactish Utilities 31 | ;; 32 | ;; Some of these are rewritten from various React addons. 33 | 34 | (defn get-props 35 | "This is the same as om.core/get-props. We added it to get around 36 | the new precondition in Om 0.8.0." 37 | [x] 38 | (aget (.-props x) "__om_cursor")) 39 | 40 | (s/defn om-component? :- s/Bool 41 | [x] 42 | (boolean (get-props x))) 43 | 44 | (s/defn strict-valid-component? :- s/Bool 45 | "TODO: Once Om updates its externs to include this file, we can 46 | remove the janky aget call." 47 | [child] 48 | ((aget js/React "isValidElement") child)) 49 | 50 | (s/defn valid-component? :- s/Bool 51 | "Returns true if the supplied argument is a valid React component, 52 | false otherwise." 53 | [child] 54 | (or (string? child) 55 | (number? child) 56 | (strict-valid-component? child))) 57 | 58 | (s/defn some-valid-component? :- s/Bool 59 | "Returns true if the supplied sequence contains some valid React component, 60 | false otherwise." 61 | [children] 62 | (boolean (some valid-component? children))) 63 | 64 | ;; TODO: We want to generate a map-valid-component, we have to hook 65 | ;; into the implementation of the internal one that can handle numbers 66 | ;; and strings properly. 67 | 68 | (defn chain-fns 69 | "Generates a new function that calls each supplied side-effecting 70 | function." 71 | [l r] 72 | (if (and l r) 73 | (fn [& args] 74 | (apply l args) 75 | (apply r args)) 76 | (or l r))) 77 | 78 | (def react-merges 79 | "Map of React keyword to a custom function for its merge. Tries to 80 | do a decent job with event handlers as well; currently only 81 | handles :on-select :on-click, :on-blur, kebab-cased as om-tools 82 | prefers." 83 | (let [merge-class (fn [l r] (str l " " r)) 84 | orig-fn (fn [l r] (or l r)) 85 | empty-fn (fn [_ _] nil)] 86 | {:className merge-class 87 | :class merge-class 88 | :style merge 89 | :children empty-fn 90 | :key empty-fn 91 | :ref orig-fn 92 | :on-select chain-fns 93 | :on-click chain-fns 94 | :on-blur chain-fns})) 95 | 96 | (defn merge-props 97 | "Merges two maps that represent React properties. Merges occur 98 | according to the functions defined in `react-merges`." 99 | [& prop-maps] 100 | (letfn [(react-merge [xs] 101 | (merge-with-fns react-merges xs)) 102 | (normalize-class [m] 103 | (if (contains? m :class) 104 | (react-merge [(dissoc m :class) {:className (:class m)}]) 105 | m))] 106 | (let [ret (react-merge (map normalize-class prop-maps))] 107 | (if-not (:key ret) 108 | (dissoc ret :key) 109 | ret)))) 110 | 111 | ;; ## clone-with-props and helpers 112 | 113 | (defn copy-js 114 | "Returns a basic, shallow copy of the supplied JS object." 115 | [arr] 116 | (let [ret (js-obj)] 117 | (doseq [k (js-keys arr)] 118 | (when (.hasOwnProperty arr k) 119 | (aset ret k (aget arr k)))) 120 | ret)) 121 | 122 | (defn create-element 123 | ([child] (create-element child nil)) 124 | ([child props] 125 | (.createElement js/React (.-type child) props))) 126 | 127 | (defn clone-om 128 | "Merges the supplied extra properties into the underlying Om cursor 129 | and calls the constructor to clone the React component. 130 | 131 | Requires that the supplied child has an Om cursor attached to it! " 132 | [child extra-props] 133 | (let [om-props (get-props child) 134 | props #js {} 135 | cloned-child (gobject/clone child)] 136 | (gobject/extend props 137 | (.-props child) 138 | #js {:__om_cursor (if (fn? extra-props) 139 | (extra-props om-props) 140 | (merge-props om-props extra-props))}) 141 | (gobject/extend cloned-child #js {:props props}) 142 | cloned-child)) 143 | 144 | (defn clone-basic-react 145 | "This function is called if the React component child was NOT 146 | generated by Om. Merges the supplied properties into the -props 147 | field of the supplied React component and creates a shallow copy." 148 | [child extra-props] 149 | (let [props (js->clj (.-props child) :keywordize-keys true) 150 | new-props (merge (if (fn? extra-props) 151 | (extra-props props) 152 | (merge-props props extra-props)) 153 | (when-let [children (:children props)] 154 | {:children children}))] 155 | (create-element child (clj->js new-props)))) 156 | 157 | (defn clone-with-props 158 | "Returns a shallow copy of the supplied component (child); the copy 159 | will have any props provided by extra-props merged in. Props are 160 | merged in the same manner as merge-props, so props like :class will 161 | be merged intelligently. 162 | 163 | extra-props can be a function of the old props that returns new 164 | props, OR it can be a map of props. 165 | 166 | If the supplied child is an Om component, any supplied extra 167 | properties will be merged into the underlying cursor and accessible 168 | in the Om constructor." 169 | ([child] 170 | (clone-with-props child {})) 171 | ([child extra-props] 172 | (cond (not (strict-valid-component? child)) child 173 | (om-component? child) (clone-om child extra-props) 174 | (and (map? extra-props) 175 | (empty? extra-props)) (create-element child (.-props child)) 176 | :else (clone-basic-react child extra-props)))) 177 | -------------------------------------------------------------------------------- /system.properties: -------------------------------------------------------------------------------- 1 | java.runtime.version=1.7 -------------------------------------------------------------------------------- /test/om_bootstrap/input_test.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.input-test 2 | (:require [cemerick.cljs.test :as t 3 | :refer-macros [deftest is use-fixtures]] 4 | [schema.test :as st])) 5 | 6 | (use-fixtures :once st/validate-schemas) 7 | 8 | (deftest numeric-equal-test 9 | (is (= 1 1) "One equals one!")) 10 | -------------------------------------------------------------------------------- /test/om_bootstrap/types_test.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.types-test 2 | (:require [cemerick.cljs.test :refer-macros [deftest is]] 3 | [om-bootstrap.types :as t] 4 | [schema.core :as s])) 5 | 6 | (deftest schema-keys-test 7 | (is (= #{:a :b :c} 8 | (set (t/schema-keys 9 | {:a "a!" 10 | (s/optional-key :b) "b!" 11 | (s/optional-key :c) "b!"}))) 12 | "Schema keys returns all keys with optionals unwrapped.")) 13 | 14 | (deftest bootstrap-test 15 | (let [attrs {:first-key "ay" 16 | :second-key "bee"}] 17 | (is (= (t/at-least 18 | (merge t/BootstrapClass attrs)) 19 | (t/bootstrap attrs)) 20 | "Usually, t/bootstrap just tacks on some extra optional fields 21 | and an s/Any s/Any pair so that extra items won't fail 22 | validation.") 23 | 24 | (is (= (t/at-least 25 | {:bs-style (s/enum "cake" "face") 26 | (s/optional-key :bs-size) t/BSSize 27 | (s/optional-key :bs-class) t/BSClass}) 28 | (t/bootstrap {:bs-style (s/enum "cake" "face")})) 29 | "If the input schema contains one of the optional keys, its 30 | value will override the default optional key."))) 31 | 32 | (deftest separate-test 33 | (is (= (t/separate t/BootstrapClass 34 | {:bs-class "face" :a "b"}) 35 | [{:bs-class "face"} {:a "b"}])) 36 | 37 | (is (= (t/separate t/BootstrapClass 38 | {:bs-class "face" :a "b"} 39 | {:bs-style "ace" :bs-class "one" :v "d"}) 40 | [{:bs-style "ace", :bs-class "face"} {:v "d", :a "b"}]))) 41 | -------------------------------------------------------------------------------- /test/om_bootstrap/util_test.cljs: -------------------------------------------------------------------------------- 1 | (ns om-bootstrap.util-test 2 | (:require [cemerick.cljs.test :as t 3 | :refer-macros [deftest is are use-fixtures]] 4 | [om.core :as om :refer-macros [component]] 5 | [om-bootstrap.button :refer [dropdown]] 6 | [om-bootstrap.util :as u] 7 | [om-tools.core :refer-macros [defcomponentk]] 8 | [om-tools.dom :as d :include-macros true] 9 | [schema.test :as st])) 10 | 11 | ;; ## Utilities (lifted from om-tools.dom-test) 12 | 13 | (def +react-dom-prototype+ (.-prototype (js/React.DOM.span nil))) 14 | 15 | (defn react-dom? [x] 16 | (and x (= (.-prototype x) +react-dom-prototype+))) 17 | 18 | (defn props [el] 19 | (js->clj (.-props el) :keywordize-keys true)) 20 | 21 | (defn children [el] 22 | (:children (props el))) 23 | 24 | (defn is=el [el1 el2] 25 | (is (= (.-tagName el1) (.-tagName el2))) 26 | (let [el1-props (props el1) 27 | el2-props (props el2) 28 | el1-children (:children el1-props) 29 | el2-children (:children el2-props)] 30 | 31 | (is (= (dissoc el1-props :children) 32 | (dissoc el2-props :children))) 33 | 34 | (cond 35 | (every? coll? [el1-children el2-children]) 36 | (doseq [[c1 c2] (map vector (:children el1-props) (:children el2-props))] 37 | (is=el c1 c2)) 38 | 39 | (every? react-dom? [el1-children el2-children]) 40 | (is=el el1-children el2-children) 41 | 42 | :else (is (= el1-children el2-children))))) 43 | 44 | ;; ## Tests 45 | 46 | (deftest merge-with-fns-test 47 | (is (= (u/merge-with-fns {:a +, :b -} 48 | [{:a 1 :b 10} 49 | {:a 2 :c "hi!"} 50 | {:a 3 :b 5 :c "ho!"}]) 51 | {:a 6, :b 5, :c "ho!"}) 52 | "merge-with-fns: If the supplied function map has a function to 53 | merge with, use that. Otherwise, right wins.")) 54 | 55 | (deftest collectify-test 56 | "Collectify coerces items to collections. Because sets aren't 57 | ordered they get wrapped in their own fresh vector, just like maps." 58 | (are [coll result] 59 | (= result (u/collectify coll)) 60 | '(1 2 3) '(1 2 3) 61 | [5 5] [5 5] 62 | "aaa" ["aaa"] 63 | {:a 1 :b 2} [{:a 1 :b 2}] 64 | #{1 2 3} [#{1 2 3}])) 65 | 66 | (deftest valid-component-test 67 | (is (u/strict-valid-component? (d/div {} "Something."))) 68 | (is (not (u/strict-valid-component? "String!")) 69 | "Strings are valid components, but not strict valid 70 | components.") 71 | (is (and (u/valid-component? "face") 72 | (u/valid-component? 123123) 73 | (u/valid-component? (d/p "a paragraph."))) 74 | "Strings are numbers are valid components; react wraps them 75 | internally.") 76 | (is (not (u/valid-component? nil))) 77 | (is (u/some-valid-component? [1 2 nil])) 78 | (is (not (u/some-valid-component? [nil nil])))) 79 | 80 | (deftest chain-fns-test 81 | (let [counter (atom 0) 82 | adder (fn [] (swap! counter inc)) 83 | double-adder (u/chain-fns adder adder)] 84 | (is (zero? @counter) "The counter starts at zero.") 85 | (adder) 86 | (is (= 1 @counter) 87 | "Calling the basic adder functions increments the counter by 1.") 88 | (double-adder) 89 | (is (= 3 @counter) 90 | "The chained version executes the side effects of `adder` 91 | twice, incrementing the counter by two more."))) 92 | 93 | (deftest om-component-test 94 | [] 95 | (is (not (u/om-component? (d/p "Just a p")))) 96 | (is (u/om-component? (dropdown {:title "Title!"})))) 97 | 98 | (deftest merge-props-test 99 | (is (= (u/merge-props {:face "cake" :class "first"} 100 | {:cake "face" :className "second"}) 101 | {:face "cake" :className "first second" :cake "face"}) 102 | "When properties merge, they normalize :class -> :className and 103 | properly merge classes.")) 104 | 105 | (defcomponentk fake-div [[:data x y z]] 106 | (render [_] (d/div {} (str "I got these numbers: " x y z)))) 107 | 108 | (deftest clone-with-props-test 109 | "Clone with props clones both Om components and standard React 110 | components." 111 | (let [prop-map {:a "a" :b "b" :className "face"}] 112 | (is (= prop-map 113 | (-> (props (d/div prop-map "div.")) 114 | (dissoc :children))) 115 | "Props returns the element's React props.") 116 | "Cloning the elements returns an element that acts the same." 117 | (is=el (d/div prop-map (d/p "Clever!")) 118 | (u/clone-with-props (d/div prop-map (d/p "Clever!")))) 119 | 120 | "Cloning with EXTRA props merges those props into the value that 121 | was cloned. Note that the classes merge together as expected." 122 | (is=el (d/div {:a "b" :extra "value" :class "cake walrus"} 123 | (d/p "Clever!")) 124 | (-> (d/div {:a "b" :class "cake"} (d/p "Clever!")) 125 | (u/clone-with-props {:extra "value" 126 | :class "walrus"}))) 127 | 128 | (is (= {:x "one" :y "two" :z "three"} 129 | (u/get-props (->fake-div {:x "one" :y "two" :z "three"}))) 130 | "u/get-props returns the inner Om props, as expected. These 131 | are trapped inside the actual props in a field called 132 | __om_cursor.") 133 | 134 | (let [om-component (->fake-div {:x "one" :y "two" :z "three" :className "cake"})] 135 | "Cloning an Om component works too." 136 | (is=el om-component (u/clone-with-props om-component))) 137 | 138 | (is (= {:x "alpha", :y "two", :z "three", :className "cake walrus"} 139 | (-> (->fake-div {:x "one" :y "two" :z "three" 140 | :class "cake"}) 141 | (u/clone-with-props {:x "alpha", :class "walrus"}) 142 | (u/get-props))) 143 | "Cloning an om component merges the extra properties into the 144 | cursor, NOT into the overall props.") 145 | 146 | (let [hut-the-vals (fn [m] 147 | (->> (map (fn [[k v]] 148 | [k (str v "-hut!")]) 149 | m) 150 | (into {})))] 151 | (is (= {:x "one-hut!" 152 | :y "two-hut!" 153 | :z "three-hut!" 154 | :class "cake-hut!"} 155 | (-> (->fake-div {:x "one" :y "two" :z "three" :class "cake"}) 156 | (u/clone-with-props hut-the-vals) 157 | (u/get-props))) 158 | "clone-with-props can take a function as well. This one adds 159 | hut! onto the end of all string values. 160 | 161 | The whole :class merging only comes into play if extra attrs 162 | contains a :class as well. :class is left alone here and not 163 | converted to :className.")))) 164 | -------------------------------------------------------------------------------- /test/vendor/console-polyfill.js: -------------------------------------------------------------------------------- 1 | // Console-polyfill. MIT license. 2 | // https://github.com/paulmillr/console-polyfill 3 | // Make it safe to do console.log() always. 4 | (function (con) { 5 | 'use strict'; 6 | var prop, method; 7 | var empty = {}; 8 | var dummy = function() {}; 9 | var properties = 'memory'.split(','); 10 | var methods = ('assert,count,debug,dir,dirxml,error,exception,group,' + 11 | 'groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,' + 12 | 'time,timeEnd,trace,warn').split(','); 13 | while (prop = properties.pop()) con[prop] = con[prop] || empty; 14 | while (method = methods.pop()) con[method] = con[method] || dummy; 15 | })(window.console = window.console || {}); 16 | -------------------------------------------------------------------------------- /test/vendor/es5-sham.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * https://github.com/es-shims/es5-shim 3 | * @license es5-shim Copyright 2009-2014 by contributors, MIT License 4 | * see https://github.com/es-shims/es5-shim/blob/master/LICENSE 5 | */ 6 | 7 | // vim: ts=4 sts=4 sw=4 expandtab 8 | 9 | //Add semicolon to prevent IIFE from being passed as argument to concated code. 10 | ; 11 | // Module systems magic dance 12 | (function (definition) { 13 | // RequireJS 14 | if (typeof define == "function") { 15 | define(definition); 16 | // YUI3 17 | } else if (typeof YUI == "function") { 18 | YUI.add("es5-sham", definition); 19 | // CommonJS and