diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..e0cd4518805a746f81b26e83c87c82426157fab2 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,11 @@ +build-android: + stage: build + tags: + - nix + - linux + script: + - cd obelisk + - nix-build -A android.frontend -o result-android + artifacts: + paths: + - obelisk/result-android/android-app-debug.apk diff --git a/obelisk/.gitignore b/obelisk/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..fa491075ade27a5b99b0b9e9c6a8845f39393647 --- /dev/null +++ b/obelisk/.gitignore @@ -0,0 +1,16 @@ +.attr-cache +.cabal-sandbox +*.hi +*.o +cabal.project.local +cabal.sandbox.config +ctags +dist-newstyle/ +dist/ +ghcid-output.txt +profile/ +result +result-* +tags +TAGS +static.out diff --git a/obelisk/.obelisk/impl/default.nix b/obelisk/.obelisk/impl/default.nix new file mode 100644 index 0000000000000000000000000000000000000000..2b4d4ab11148e306f1f2f6acd94168ec417507e7 --- /dev/null +++ b/obelisk/.obelisk/impl/default.nix @@ -0,0 +1,2 @@ +# DO NOT HAND-EDIT THIS FILE +import (import ./thunk.nix) \ No newline at end of file diff --git a/obelisk/.obelisk/impl/github.json b/obelisk/.obelisk/impl/github.json new file mode 100644 index 0000000000000000000000000000000000000000..e2d81dd7c9e110bf21f9d18d32a933d2c776735b --- /dev/null +++ b/obelisk/.obelisk/impl/github.json @@ -0,0 +1,8 @@ +{ + "owner": "obsidiansystems", + "repo": "obelisk", + "branch": "master", + "private": false, + "rev": "41f97410cfa2e22a4ed9e9344abcd58bbe0f3287", + "sha256": "04bpzji7y3nz573ib3g6icb56s5zbj4zxpakhqaql33v2v77hi9g" +} diff --git a/obelisk/.obelisk/impl/thunk.nix b/obelisk/.obelisk/impl/thunk.nix new file mode 100644 index 0000000000000000000000000000000000000000..bbf2dc18fbbea1ae35515c775663a8d95dcc23c5 --- /dev/null +++ b/obelisk/.obelisk/impl/thunk.nix @@ -0,0 +1,9 @@ +# DO NOT HAND-EDIT THIS FILE +let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: + if !fetchSubmodules && !private then builtins.fetchTarball { + url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; + } else (import <nixpkgs> {}).fetchFromGitHub { + inherit owner repo rev sha256 fetchSubmodules private; + }; + json = builtins.fromJSON (builtins.readFile ./github.json); +in fetch json \ No newline at end of file diff --git a/obelisk/backend/backend.cabal b/obelisk/backend/backend.cabal new file mode 100644 index 0000000000000000000000000000000000000000..25f690346b18c8b6424530462b7df005963a9cc8 --- /dev/null +++ b/obelisk/backend/backend.cabal @@ -0,0 +1,29 @@ +name: backend +version: 0.1 +cabal-version: >= 1.8 +build-type: Simple + +library + hs-source-dirs: src + if impl(ghcjs) + buildable: False + build-depends: base + , common + , frontend + , obelisk-backend + , obelisk-route + exposed-modules: + Backend + ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -O -fno-show-valid-hole-fits + +executable backend + main-is: main.hs + hs-source-dirs: src-bin + ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -O -threaded -fno-show-valid-hole-fits + if impl(ghcjs) + buildable: False + build-depends: base + , backend + , common + , frontend + , obelisk-backend diff --git a/obelisk/backend/frontend.jsexe b/obelisk/backend/frontend.jsexe new file mode 120000 index 0000000000000000000000000000000000000000..3a9cb6fefca28481c6526dbe2f1773817e110efa --- /dev/null +++ b/obelisk/backend/frontend.jsexe @@ -0,0 +1 @@ +../frontend-js/bin/frontend.jsexe \ No newline at end of file diff --git a/obelisk/backend/frontendJs/frontend.jsexe b/obelisk/backend/frontendJs/frontend.jsexe new file mode 120000 index 0000000000000000000000000000000000000000..af9b8f4536e79ba91d3cf5610cd61c82193c36ac --- /dev/null +++ b/obelisk/backend/frontendJs/frontend.jsexe @@ -0,0 +1 @@ +../../frontend-js/bin/frontend.jsexe \ No newline at end of file diff --git a/obelisk/backend/src-bin/main.hs b/obelisk/backend/src-bin/main.hs new file mode 100644 index 0000000000000000000000000000000000000000..00f1994a2c58c5696512adbf37b8b53aa235d570 --- /dev/null +++ b/obelisk/backend/src-bin/main.hs @@ -0,0 +1,6 @@ +import Backend +import Frontend +import Obelisk.Backend + +main :: IO () +main = runBackend backend frontend diff --git a/obelisk/backend/src/Backend.hs b/obelisk/backend/src/Backend.hs new file mode 100644 index 0000000000000000000000000000000000000000..5842ce9fd410acf1d55cce3421157e122e452256 --- /dev/null +++ b/obelisk/backend/src/Backend.hs @@ -0,0 +1,10 @@ +module Backend where + +import Common.Route +import Obelisk.Backend + +backend :: Backend BackendRoute FrontendRoute +backend = Backend + { _backend_run = \serve -> serve $ const $ return () + , _backend_routeEncoder = fullRouteEncoder + } diff --git a/obelisk/backend/static b/obelisk/backend/static new file mode 120000 index 0000000000000000000000000000000000000000..4dab1644d836089c02492f343a6b50701ecd7e08 --- /dev/null +++ b/obelisk/backend/static @@ -0,0 +1 @@ +../static \ No newline at end of file diff --git a/obelisk/cabal.project b/obelisk/cabal.project new file mode 100644 index 0000000000000000000000000000000000000000..fe0438b092ccb8bf97c085da63c8aad4a45d2a51 --- /dev/null +++ b/obelisk/cabal.project @@ -0,0 +1,3 @@ +optional-packages: + * +write-ghc-environment-files: never diff --git a/obelisk/common/common.cabal b/obelisk/common/common.cabal new file mode 100644 index 0000000000000000000000000000000000000000..82b89916cc3d7ffefc81ef2e36d48a1d0efea0d3 --- /dev/null +++ b/obelisk/common/common.cabal @@ -0,0 +1,15 @@ +name: common +version: 0.1 +cabal-version: >= 1.2 +build-type: Simple + +library + hs-source-dirs: src + build-depends: base + , obelisk-route + , mtl + , text + exposed-modules: + Common.Api + Common.Route + ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -O -fno-show-valid-hole-fits diff --git a/obelisk/common/src/Common/Api.hs b/obelisk/common/src/Common/Api.hs new file mode 100644 index 0000000000000000000000000000000000000000..1ea3df09d4ecfd052f8142b1ef7efa4da4f1b883 --- /dev/null +++ b/obelisk/common/src/Common/Api.hs @@ -0,0 +1,4 @@ +module Common.Api where + +commonStuff :: String +commonStuff = "Here is a string defined in Common.Api" diff --git a/obelisk/common/src/Common/Route.hs b/obelisk/common/src/Common/Route.hs new file mode 100644 index 0000000000000000000000000000000000000000..1dce9a734d13742970c78fbe0672fab8699613bd --- /dev/null +++ b/obelisk/common/src/Common/Route.hs @@ -0,0 +1,47 @@ +{-# LANGUAGE EmptyCase #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeFamilies #-} +module Common.Route where + +{- -- You will probably want these imports for composing Encoders. +import Prelude hiding (id, (.)) +import Control.Category +-} + +import Data.Text (Text) +import Data.Functor.Identity + +import Obelisk.Route +import Obelisk.Route.TH + +data BackendRoute :: * -> * where + -- | Used to handle unparseable routes. + BackendRoute_Missing :: BackendRoute () + -- You can define any routes that will be handled specially by the backend here. + -- i.e. These do not serve the frontend, but do something different, such as serving static files. + +data FrontendRoute :: * -> * where + FrontendRoute_Main :: FrontendRoute () + -- This type is used to define frontend routes, i.e. ones for which the backend will serve the frontend. + +fullRouteEncoder + :: Encoder (Either Text) Identity (R (FullRoute BackendRoute FrontendRoute)) PageName +fullRouteEncoder = mkFullRouteEncoder + (FullRoute_Backend BackendRoute_Missing :/ ()) + (\case + BackendRoute_Missing -> PathSegment "missing" $ unitEncoder mempty) + (\case + FrontendRoute_Main -> PathEnd $ unitEncoder mempty) + +concat <$> mapM deriveRouteComponent + [ ''BackendRoute + , ''FrontendRoute + ] diff --git a/obelisk/config/common/example b/obelisk/config/common/example new file mode 100644 index 0000000000000000000000000000000000000000..e368f70d7fc7e42f8e5971f99f569cfd98650669 --- /dev/null +++ b/obelisk/config/common/example @@ -0,0 +1 @@ +This string comes from config/common/example \ No newline at end of file diff --git a/obelisk/config/common/route b/obelisk/config/common/route new file mode 100644 index 0000000000000000000000000000000000000000..99298a3da0b5cf8684f3169b08315af328a13012 --- /dev/null +++ b/obelisk/config/common/route @@ -0,0 +1 @@ +http://localhost:8000 \ No newline at end of file diff --git a/obelisk/config/readme.md b/obelisk/config/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..7ca5a54b35175a22b1fa4ae4f62bed167da081e5 --- /dev/null +++ b/obelisk/config/readme.md @@ -0,0 +1,9 @@ +### Config + +Obelisk projects should contain a config folder with the following subfolders: common, frontend, and backend. + +Things that should never be transmitted to the frontend belong in backend/ (e.g., email credentials) + +Frontend-only configuration belongs in frontend/. + +Shared configuration files (e.g., the route config) belong in common/ diff --git a/obelisk/default.nix b/obelisk/default.nix new file mode 100644 index 0000000000000000000000000000000000000000..3a4a76953486198a84c313f5cde1a41bf9b62a60 --- /dev/null +++ b/obelisk/default.nix @@ -0,0 +1,25 @@ +{ system ? builtins.currentSystem +, obelisk ? import ./.obelisk/impl { + inherit system; + iosSdkVersion = "13.2"; + + # You must accept the Android Software Development Kit License Agreement at + # https://developer.android.com/studio/terms in order to build Android apps. + # Uncomment and set this to `true` to indicate your acceptance: + config.android_sdk.accept_license = true; + + # In order to use Let's Encrypt for HTTPS deployments you must accept + # their terms of service at https://letsencrypt.org/repository/. + # Uncomment and set this to `true` to indicate your acceptance: + # terms.security.acme.acceptTerms = false; + } +}: +with obelisk; +project ./. ({ ... }: { + # Not using "storage.private" (our newer domain name) since that makes the build + # fail: "[...] is not a valid Java package name as 'private' is a Java keyword." + android.applicationId = "io.privatestorage.privatestoragemobile"; + android.displayName = "Private Storage Mobile"; + ios.bundleIdentifier = "systems.obsidian.obelisk.examples.minimal"; + ios.bundleName = "Obelisk Minimal Example"; +}) diff --git a/obelisk/frontend/frontend.cabal b/obelisk/frontend/frontend.cabal new file mode 100644 index 0000000000000000000000000000000000000000..ba6e5e07040707c2f93f7cc96c0a3a881a1ef20a --- /dev/null +++ b/obelisk/frontend/frontend.cabal @@ -0,0 +1,36 @@ +name: frontend +version: 0.1 +cabal-version: >= 1.8 +build-type: Simple + +library + hs-source-dirs: src + build-depends: base + , common + , obelisk-frontend + , obelisk-route + , jsaddle + , reflex-dom-core + , obelisk-executable-config-lookup + , obelisk-generated-static + , text + exposed-modules: + Frontend + ghc-options: -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -O -fno-show-valid-hole-fits + +executable frontend + main-is: main.hs + hs-source-dirs: src-bin + build-depends: base + , common + , obelisk-frontend + , obelisk-route + , reflex-dom + , obelisk-generated-static + , frontend + ghc-options: -threaded -O -Wall -Wredundant-constraints -Wincomplete-uni-patterns -Wincomplete-record-updates -fno-show-valid-hole-fits + if impl(ghcjs) + ghc-options: -dedupe + cpp-options: -DGHCJS_BROWSER + if os(darwin) + ghc-options: -dynamic diff --git a/obelisk/frontend/src-bin/main.hs b/obelisk/frontend/src-bin/main.hs new file mode 100644 index 0000000000000000000000000000000000000000..9408dc315a894bc7657b2e3a6f7ea7f0d331e2b8 --- /dev/null +++ b/obelisk/frontend/src-bin/main.hs @@ -0,0 +1,10 @@ +import Frontend +import Common.Route +import Obelisk.Frontend +import Obelisk.Route.Frontend +import Reflex.Dom + +main :: IO () +main = do + let Right validFullEncoder = checkEncoder fullRouteEncoder + run $ runFrontend validFullEncoder frontend diff --git a/obelisk/frontend/src/Frontend.hs b/obelisk/frontend/src/Frontend.hs new file mode 100644 index 0000000000000000000000000000000000000000..b5453787ad5794d77047cc4ec7bb0e8963e1bd58 --- /dev/null +++ b/obelisk/frontend/src/Frontend.hs @@ -0,0 +1,47 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TemplateHaskell #-} + +module Frontend where + +import Control.Monad +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import Language.Javascript.JSaddle (eval, liftJSM) + +import Obelisk.Frontend +import Obelisk.Configs +import Obelisk.Route +import Obelisk.Generated.Static + +import Reflex.Dom.Core + +import Common.Api +import Common.Route + + +-- This runs in a monad that can be run on the client or the server. +-- To run code in a pure client or pure server context, use one of the +-- `prerender` functions. +frontend :: Frontend (R FrontendRoute) +frontend = Frontend + { _frontend_head = do + el "title" $ text "Obelisk Minimal Example" + elAttr "link" ("href" =: $(static "main.css") <> "type" =: "text/css" <> "rel" =: "stylesheet") blank + , _frontend_body = do + el "h1" $ text "Welcome to Obelisk!" + el "p" $ text $ T.pack commonStuff + + -- `prerender` and `prerender_` let you choose a widget to run on the server + -- during prerendering and a different widget to run on the client with + -- JavaScript. The following will generate a `blank` widget on the server and + -- print "Hello, World!" on the client. + prerender_ blank $ liftJSM $ void $ eval ("console.log('Hello, World!')" :: T.Text) + + elAttr "img" ("src" =: $(static "obelisk.jpg")) blank + el "div" $ do + exampleConfig <- getConfig "common/example" + case exampleConfig of + Nothing -> text "No config file found in config/common/example" + Just s -> text $ T.decodeUtf8 s + return () + } diff --git a/obelisk/static/main.css b/obelisk/static/main.css new file mode 100644 index 0000000000000000000000000000000000000000..57c2d532160ad790e1b05f47342c36297a6ddafb --- /dev/null +++ b/obelisk/static/main.css @@ -0,0 +1,3 @@ +p { + color: red; +} \ No newline at end of file diff --git a/obelisk/static/obelisk.jpg b/obelisk/static/obelisk.jpg new file mode 100644 index 0000000000000000000000000000000000000000..68c8682d0809b5265fef807bdb8d46c9829e55ed Binary files /dev/null and b/obelisk/static/obelisk.jpg differ