├── .gitignore
├── README.md
├── build.sbt
├── deploy.sh
├── index.html
├── index.js
├── package.json
├── project
├── build.properties
└── plugins.sbt
├── src
└── main
│ └── scala
│ └── scalajsreact
│ └── template
│ ├── ReactApp.scala
│ ├── components
│ ├── Footer.scala
│ ├── LeftNav.scala
│ ├── TopNav.scala
│ └── items
│ │ ├── Item1Data.scala
│ │ ├── Item2Data.scala
│ │ └── ItemsInfo.scala
│ ├── css
│ ├── AppCSS.scala
│ └── GlobalStyle.scala
│ ├── models
│ └── Menu.scala
│ ├── pages
│ ├── HomePage.scala
│ └── ItemsPage.scala
│ └── routes
│ ├── AppRouter.scala
│ └── Item.scala
├── webpack.config.js
└── webpack.config.min.js
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 | *.log
3 |
4 | # sbt specific
5 | .cache/
6 | .history/
7 | .lib/
8 | dist/*
9 | target/
10 | lib_managed/
11 | src_managed/
12 | project/boot/
13 | project/plugins/project/
14 |
15 | # Scala-IDE specific
16 | .scala_dependencies
17 | .worksheet
18 |
19 | #Mac
20 | .DS_Store
21 |
22 | #intellij idea
23 | .idea
24 | .idea_modules
25 |
26 | #project
27 | js/*
28 | node_modules/*
29 | build/*
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | scalajs-react-template
2 | ======================
3 |
4 | Basic skeleton app for scalajs-react and scalacss and webpack
5 |
6 | How To :
7 |
8 | ```js
9 |
10 | npm install
11 |
12 | npm run build
13 |
14 | npm start
15 |
16 | //in new terminal
17 | sbt ~fastOptJS
18 |
19 | //open following url in browser
20 |
21 | http://localhost:8090/webpack-dev-server/
22 |
23 |
24 | // happy coding :)
25 |
26 |
27 | ```
28 |
--------------------------------------------------------------------------------
/build.sbt:
--------------------------------------------------------------------------------
1 | enablePlugins(ScalaJSPlugin)
2 |
3 | name := "scalajs-react-template-webpack"
4 |
5 | version := "1.0"
6 |
7 | scalaVersion := "2.11.6"
8 |
9 |
10 | // create launcher file ( its search for object extends JSApp , make sure there is only one file)
11 | persistLauncher := true
12 |
13 | persistLauncher in Test := false
14 |
15 | val scalaJSReactVersion = "0.9.0"
16 |
17 | val scalaCssVersion = "0.2.0"
18 |
19 |
20 | libraryDependencies ++= Seq("com.github.japgolly.scalajs-react" %%% "core" % scalaJSReactVersion,
21 | "com.github.japgolly.scalajs-react" %%% "extra" % scalaJSReactVersion,
22 | "com.github.japgolly.scalacss" %%% "core" % scalaCssVersion,
23 | "com.github.japgolly.scalacss" %%% "ext-react" % scalaCssVersion)
24 |
25 |
26 | // copy javascript files to js folder,that are generated using fastOptJS/fullOptJS
27 |
28 | crossTarget in (Compile, fullOptJS) := file("build")
29 |
30 | crossTarget in (Compile, fastOptJS) := file("build")
31 |
32 | crossTarget in (Compile, packageScalaJSLauncher) := file("build")
33 |
34 | artifactPath in (Compile, fastOptJS) := ((crossTarget in (Compile, fastOptJS)).value /
35 | ((moduleName in fastOptJS).value + "-opt.js"))
36 |
37 |
38 |
39 | scalacOptions += "-feature"
40 |
41 |
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 |
4 | #Handy script to deploy app to github pages(gh-pages)
5 |
6 | # get comment
7 | comment="$1"
8 |
9 | sbt clean
10 |
11 | sbt fullOptJS
12 |
13 | webpack --config webpack.config.min.js
14 |
15 | if [ "$comment" == "" ]; then
16 | comment="push form CI"
17 | echo "no comment specified to deploy, using default : $comment"
18 | fi
19 |
20 | projectName="scalajs-react-template-webpack"
21 |
22 | ghPagesPath="/Users/chandrasekharkode/Desktop/Kode/Programming/scalaprojects/chandu0101.github.io"
23 |
24 | projectPath=${ghPagesPath}/${projectName}
25 |
26 | mkdir -p ${projectPath}/build
27 |
28 | cp index.html ${projectPath}
29 |
30 | cp build/${projectName}-opt.js ${projectPath}/build/
31 |
32 | cp build/bundle.min.js ${projectPath}/build/bundle.js
33 |
34 | cp build/${projectName}-launcher.js ${projectPath}/build/
35 |
36 | cd ${ghPagesPath}
37 |
38 | git add ${projectName}
39 |
40 | git commit -m "$comment"
41 |
42 | git push
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Scalajs-react-template-webpack
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var React = require('react/addons');
2 |
3 | window.React = React;
4 |
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "scalajs-react-template-webpack",
3 | "version": "0.1.0",
4 | "description": "Sample project that uses scalajs-react and scalacss",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/chandu0101/scalajs-react-template-webpack.git"
8 | },
9 | "scripts": {
10 | "start": "webpack --watch & webpack-dev-server --hot --progress --colors --port 8090",
11 | "build": "webpack --progress --colors"
12 | },
13 | "devDependencies": {
14 | "node-libs-browser": "^0.5.2",
15 | "react-hot-loader": "^1.2.7",
16 | "webpack": "^1.9.10",
17 | "webpack-dev-server": "^1.9.0"
18 | },
19 | "dependencies": {
20 | "react": "^0.13.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version=0.13.8
--------------------------------------------------------------------------------
/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.3")
2 |
--------------------------------------------------------------------------------
/src/main/scala/scalajsreact/template/ReactApp.scala:
--------------------------------------------------------------------------------
1 | package scalajsreact.template
2 |
3 | import japgolly.scalajs.react._
4 | import org.scalajs.dom
5 |
6 | import scala.scalajs.js.JSApp
7 | import scala.scalajs.js.annotation.JSExport
8 | import scalajsreact.template.css.AppCSS
9 | import scalajsreact.template.routes.AppRouter
10 |
11 |
12 | object ReactApp extends JSApp {
13 | @JSExport
14 | override def main(): Unit = {
15 | AppCSS.load
16 | AppRouter.router().render(dom.document.body)
17 | }
18 |
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/src/main/scala/scalajsreact/template/components/Footer.scala:
--------------------------------------------------------------------------------
1 | package scalajsreact.template.components
2 |
3 | import japgolly.scalajs.react._
4 | import japgolly.scalajs.react.vdom.prefix_<^._
5 |
6 | object Footer {
7 |
8 | val component = ReactComponentB.static("Footer",
9 | <.footer(^.textAlign.center,
10 | <.div(^.borderBottom := "1px solid grey", ^.padding := "0px"),
11 | <.p(^.paddingTop := "5px", "Built using scalajs/scalajs-react/scalacss")
12 | )
13 | ).buildU
14 |
15 | def apply() = component()
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/scala/scalajsreact/template/components/LeftNav.scala:
--------------------------------------------------------------------------------
1 | package scalajsreact.template.components
2 |
3 | import japgolly.scalajs.react._
4 | import japgolly.scalajs.react.extra.Reusability
5 | import japgolly.scalajs.react.extra.router2.RouterCtl
6 | import japgolly.scalajs.react.vdom.prefix_<^._
7 |
8 | import scala.scalajs.js.{Any, UndefOr}
9 | import scalacss.Defaults._
10 | import scalacss.ScalaCssReact._
11 | import scalajsreact.template.routes.Item
12 |
13 | object LeftNav {
14 |
15 | object Style extends StyleSheet.Inline {
16 |
17 | import dsl._
18 |
19 | val container = style(display.flex,
20 | flexDirection.column,
21 | listStyle := "none",
22 | padding.`0`
23 | )
24 |
25 | val menuItem = boolStyle(selected => styleS(
26 | lineHeight(48.px),
27 | padding :=! "0 25px",
28 | cursor.pointer,
29 | textDecoration := "none",
30 | mixinIfElse(selected)(color.red,
31 | fontWeight._500)
32 | (color.black,
33 | &.hover(color("#555555".color),
34 | backgroundColor("#ecf0f1".color)))
35 | ))
36 | }
37 |
38 | case class Props(menus: Vector[Item], selectedPage: Item, ctrl: RouterCtl[Item])
39 |
40 | implicit val currentPageReuse = Reusability.by_==[Item]
41 | implicit val propsReuse = Reusability.by((_: Props).selectedPage)
42 |
43 | val component = ReactComponentB[Props]("LeftNav")
44 | .render(P => {
45 | <.div(Style.container)(
46 | P.menus.map(item => <.a(^.key := item.title,
47 | Style.menuItem(item == P.selectedPage),
48 | item.title,
49 | P.ctrl setOnClick item))
50 | )
51 | })
52 | .configure(Reusability.shouldComponentUpdate)
53 | .build
54 |
55 |
56 | def apply(props: Props, ref: UndefOr[String] = "", key: Any = {}) = component.set(key, ref)(props)
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/scala/scalajsreact/template/components/TopNav.scala:
--------------------------------------------------------------------------------
1 | package scalajsreact.template.components
2 |
3 | import scalajsreact.template.routes.AppRouter
4 | import AppRouter.AppPage
5 | import japgolly.scalajs.react._
6 | import japgolly.scalajs.react.extra.Reusability
7 | import japgolly.scalajs.react.extra.router2.RouterCtl
8 | import japgolly.scalajs.react.vdom.prefix_<^._
9 |
10 | import scala.scalajs.js
11 | import scalacss.Defaults._
12 | import scalacss.ScalaCssReact._
13 | import scalajsreact.template.routes.AppRouter
14 | import AppRouter.AppPage
15 | import scalajsreact.template.models.Menu
16 | import scalajsreact.template.routes.AppRouter.AppPage
17 |
18 |
19 | object TopNav {
20 |
21 | object Style extends StyleSheet.Inline {
22 |
23 | import dsl._
24 |
25 | val navMenu = style(display.flex,
26 | alignItems.center,
27 | backgroundColor("#F2706D"),
28 | margin.`0`,
29 | listStyle := "none")
30 |
31 | val menuItem = boolStyle(selected => styleS(
32 | padding(20.px),
33 | fontSize(1.5.em),
34 | cursor.pointer,
35 | color("rgb(244, 233, 233)"),
36 | mixinIfElse(selected)(
37 | backgroundColor("#E8433F".color),
38 | fontWeight._500)
39 | (&.hover(
40 | backgroundColor("#B6413E".color)))
41 | ))
42 |
43 | }
44 |
45 | case class Props(menus: Vector[Menu], selectedPage: AppPage, ctrl: RouterCtl[AppPage])
46 |
47 | implicit val currentPageReuse = Reusability.by_==[AppPage]
48 | implicit val propsReuse = Reusability.by((_:Props).selectedPage)
49 |
50 | val component = ReactComponentB[Props]("TopNav")
51 | .render((P) => {
52 | <.header(
53 | <.nav(
54 | <.ul(Style.navMenu,
55 | P.menus.map(item => <.li(^.key := item.name, Style.menuItem(item.route == P.selectedPage), item.name, P.ctrl setOnClick item.route)))
56 | ))
57 | })
58 | .configure(Reusability.shouldComponentUpdate)
59 | .build
60 |
61 | def apply(props: Props, ref: js.UndefOr[String] = "", key: js.Any = {}) = component.set(key, ref)(props)
62 |
63 | }
64 |
65 |
66 |
--------------------------------------------------------------------------------
/src/main/scala/scalajsreact/template/components/items/Item1Data.scala:
--------------------------------------------------------------------------------
1 | package scalajsreact.template.components.items
2 |
3 | import japgolly.scalajs.react._
4 | import japgolly.scalajs.react.vdom.prefix_<^._
5 |
6 | object Item1Data {
7 |
8 | val component = ReactComponentB.static("Item1",
9 | <.div("This is Item1 Page ")
10 | ).buildU
11 |
12 | def apply() = component()
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/scala/scalajsreact/template/components/items/Item2Data.scala:
--------------------------------------------------------------------------------
1 | package scalajsreact.template.components.items
2 |
3 | import japgolly.scalajs.react._
4 | import japgolly.scalajs.react.vdom.prefix_<^._
5 |
6 | object Item2Data {
7 |
8 | val component = ReactComponentB.static("Item2",
9 | <.div("This is Item2 Page ")
10 | ).buildU
11 |
12 | def apply() = component()
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/scala/scalajsreact/template/components/items/ItemsInfo.scala:
--------------------------------------------------------------------------------
1 | package scalajsreact.template.components.items
2 |
3 | import japgolly.scalajs.react.{ReactComponentB, _}
4 | import japgolly.scalajs.react.vdom.prefix_<^._
5 |
6 | import scalacss.Defaults._
7 | import scalacss.ScalaCssReact._
8 |
9 | object ItemsInfo {
10 |
11 | val component = ReactComponentB.static("ItemsInfo",
12 | <.div(" Items Root Page ")
13 | ).buildU
14 |
15 | def apply() = component()
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/scala/scalajsreact/template/css/AppCSS.scala:
--------------------------------------------------------------------------------
1 | package scalajsreact.template.css
2 |
3 | import scalajsreact.template.components.{TopNav, LeftNav}
4 | import scalajsreact.template.pages.{HomePage, ItemsPage}
5 |
6 | import scalacss.ScalaCssReact._
7 | import scalacss.mutable.GlobalRegistry
8 | import scalacss.Defaults._
9 |
10 | object AppCSS {
11 |
12 | def load = {
13 | GlobalRegistry.register(
14 | GlobalStyle,
15 | TopNav.Style,
16 | LeftNav.Style,
17 | ItemsPage.Style,
18 | HomePage.Style)
19 | GlobalRegistry.onRegistration(_.addToDocument())
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/scala/scalajsreact/template/css/GlobalStyle.scala:
--------------------------------------------------------------------------------
1 | package scalajsreact.template.css
2 |
3 | import scalacss.Defaults._
4 |
5 | object GlobalStyle extends StyleSheet.Inline {
6 |
7 | import dsl._
8 |
9 | style(unsafeRoot("body")(
10 | margin.`0`,
11 | padding.`0`,
12 | fontSize(14.px),
13 | fontFamily := "Roboto, sans-serif"
14 | ))
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/scala/scalajsreact/template/models/Menu.scala:
--------------------------------------------------------------------------------
1 | package scalajsreact.template.models
2 |
3 | import scalajsreact.template.routes.AppRouter
4 | import AppRouter.AppPage
5 |
6 | import scalajsreact.template.routes.AppRouter
7 |
8 | case class Menu(name: String, route: AppPage)
--------------------------------------------------------------------------------
/src/main/scala/scalajsreact/template/pages/HomePage.scala:
--------------------------------------------------------------------------------
1 | package scalajsreact.template.pages
2 |
3 | import japgolly.scalajs.react._
4 | import japgolly.scalajs.react.vdom.prefix_<^._
5 |
6 | import scala.scalajs.js
7 | import scalacss.Defaults._
8 | import scalacss.ScalaCssReact._
9 |
10 | object HomePage {
11 |
12 | object Style extends StyleSheet.Inline {
13 | import dsl._
14 | val content = style(textAlign.center,
15 | fontSize(30.px),
16 | minHeight(450.px),
17 | paddingTop(40.px))
18 | }
19 |
20 | val component = ReactComponentB.static("HomePage",
21 | <.div(Style.content, "ScalaJS-React Template with Webpack ")
22 | ).buildU
23 |
24 | def apply() = component()
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/scala/scalajsreact/template/pages/ItemsPage.scala:
--------------------------------------------------------------------------------
1 | package scalajsreact.template.pages
2 |
3 | import japgolly.scalajs.react._
4 | import japgolly.scalajs.react.extra.router2.RouterCtl
5 | import japgolly.scalajs.react.vdom.prefix_<^._
6 | import scala.scalajs.js
7 | import scalacss.Defaults._
8 | import scalacss.ScalaCssReact._
9 | import scalajsreact.template.components.LeftNav
10 | import scalajsreact.template.routes.Item
11 |
12 | object ItemsPage {
13 |
14 | object Style extends StyleSheet.Inline {
15 | import dsl._
16 | val container = style(
17 | display.flex,
18 | minHeight(600.px))
19 |
20 | val nav = style(width(190.px),
21 | borderRight :=! "1px solid rgb(223, 220, 220)")
22 |
23 | val content = style(padding(30.px))
24 | }
25 |
26 | val component = ReactComponentB[Props]("ItemsPage")
27 | .render(P => {
28 | <.div(Style.container,
29 | <.div(Style.nav, LeftNav(LeftNav.Props(Item.menu,P.selectedPage,P.ctrl))),
30 | <.div(Style.content, P.selectedPage.render())
31 | )
32 | })
33 | .build
34 |
35 | case class Props(selectedPage : Item,ctrl : RouterCtl[Item])
36 |
37 | def apply(props : Props,ref: js.UndefOr[String] = "", key: js.Any = {}) = component.set(key, ref)(props)
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/scala/scalajsreact/template/routes/AppRouter.scala:
--------------------------------------------------------------------------------
1 | package scalajsreact.template.routes
2 |
3 | import japgolly.scalajs.react.extra.router2.{Resolution, RouterConfigDsl, RouterCtl, _}
4 | import japgolly.scalajs.react.vdom.prefix_<^._
5 |
6 | import scalajsreact.template.components.{TopNav, Footer}
7 | import scalajsreact.template.models.Menu
8 | import scalajsreact.template.pages.HomePage
9 |
10 | object AppRouter {
11 |
12 | sealed trait AppPage
13 |
14 | case object Home extends AppPage
15 | case class Items(p : Item) extends AppPage
16 |
17 |
18 | val config = RouterConfigDsl[AppPage].buildConfig { dsl =>
19 | import dsl._
20 | val itemRoutes : Rule = Item.routes.prefixPath_/("#items").pmap[AppPage](Items){ case Items(p) => p}
21 | (trimSlashes
22 | | staticRoute(root, Home) ~> render(HomePage())
23 | | itemRoutes
24 | ).notFound(redirectToPage(Home)(Redirect.Replace))
25 | .renderWith(layout)
26 | }
27 |
28 |
29 | val mainMenu = Vector(
30 | Menu("Home",Home),
31 | Menu("Items",Items(Item.Info))
32 | )
33 |
34 |
35 | def layout(c: RouterCtl[AppPage], r: Resolution[AppPage]) = {
36 | <.div(
37 | TopNav(TopNav.Props(mainMenu,r.page,c)),
38 | r.render(),
39 | Footer()
40 | )
41 | }
42 |
43 | val baseUrl = BaseUrl.fromWindowOrigin / "scalajs-react-template-webpack/"
44 |
45 | val router = Router(baseUrl, config)
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/scala/scalajsreact/template/routes/Item.scala:
--------------------------------------------------------------------------------
1 | package scalajsreact.template.routes
2 |
3 | import japgolly.scalajs.react.ReactElement
4 | import japgolly.scalajs.react.extra.router2.RouterConfigDsl
5 |
6 | import scalajsreact.template.components.Footer
7 | import scalajsreact.template.components.items.{ItemsInfo, Item1Data, Item2Data}
8 | import scalajsreact.template.pages.ItemsPage
9 |
10 | sealed abstract class Item(val title: String,
11 | val routerPath: String,
12 | val render: () => ReactElement)
13 |
14 |
15 | object Item {
16 |
17 | case object Info extends Item("Info","info",() => ItemsInfo())
18 |
19 | case object Item1 extends Item("Item1","item1",() => Item1Data())
20 |
21 | case object Item2 extends Item("Item2","item2",() => Item2Data())
22 |
23 | val menu = Vector(Info,Item1,Item2)
24 |
25 | val routes = RouterConfigDsl[Item].buildRule { dsl =>
26 | import dsl._
27 |
28 | menu.map(i =>
29 | staticRoute(i.routerPath, i) ~> renderR(r => ItemsPage(props = ItemsPage.Props(i, r)))
30 | ).reduce(_ | _)
31 |
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var webpack = require('webpack');
4 |
5 | module.exports = {
6 |
7 | entry: [
8 | 'webpack/hot/only-dev-server',
9 | './index.js'
10 | ],
11 | output: {
12 | path: __dirname + '/build',
13 | publicPath: __dirname + "/build/",
14 | filename: 'bundle.js'
15 | },
16 | plugins: [
17 | new webpack.HotModuleReplacementPlugin(),
18 | new webpack.NoErrorsPlugin()
19 | ]
20 |
21 |
22 | };
--------------------------------------------------------------------------------
/webpack.config.min.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var webpack = require('webpack');
4 |
5 | module.exports = {
6 |
7 | entry: [
8 | './index.js'
9 | ],
10 | output: {
11 | path: __dirname + '/build',
12 | publicPath: __dirname + "/build/",
13 | filename: 'bundle.min.js'
14 | },
15 | plugins: [
16 | new webpack.NoErrorsPlugin(),
17 | new webpack.optimize.UglifyJsPlugin({minimize: true})
18 | ]
19 |
20 |
21 | };
--------------------------------------------------------------------------------