ihp-ide-1.4.0: IHP/IDE/CodeGen/ApplicationGenerator.hs
module IHP.IDE.CodeGen.ApplicationGenerator (buildPlan) where
import IHP.Prelude
import IHP.IDE.CodeGen.Types
buildPlan :: Text -> IO (Either Text [GeneratorAction])
buildPlan applicationName =
if (null applicationName)
then do
pure $ Left "Application name cannot be empty"
else do
let applicationName' = ucfirst applicationName
pure $ Right $ generateGenericApplication applicationName'
generateGenericApplication :: Text -> [GeneratorAction]
generateGenericApplication applicationName =
let
typesHs =
"module " <> applicationName <> ".Types where\n\n"
<> "import IHP.Prelude\n"
<> "import IHP.ModelSupport\n"
<> "import Generated.Types\n\n"
<> "data " <> applicationName <> "Application = " <> applicationName <> "Application deriving (Eq, Show)\n\n"
<> "\n"
<> "data StaticController = WelcomeAction deriving (Eq, Show, Data)"
<> "\n"
routesHs =
"module " <> applicationName <> ".Routes where\n"
<> "import IHP.RouterPrelude\n"
<> "import Generated.Types\n"
<> "import " <> applicationName <> ".Types\n\n"
<> "-- Generator Marker\n"
<> "instance AutoRoute StaticController"
frontControllerHs =
"module " <> applicationName <> ".FrontController where\n\n"
<> "import IHP.RouterPrelude\n"
<> "import " <> applicationName <> ".Controller.Prelude\n"
<> "import " <> applicationName <> ".View.Layout (defaultLayout)\n\n"
<> "-- Controller Imports\n"
<> "import " <> applicationName <> ".Controller.Static\n\n"
<> "instance FrontController " <> applicationName <> "Application where\n"
<> " controllers = \n"
<> " [ startPage WelcomeAction\n"
<> " -- Generator Marker\n"
<> " ]\n\n"
<> "instance InitControllerContext " <> applicationName <> "Application where\n"
<> " initContext = do\n"
<> " setLayout defaultLayout\n"
<> " initAutoRefresh\n"
controllerPreludeHs =
"module " <> applicationName <> ".Controller.Prelude\n"
<> "( module " <> applicationName <> ".Types\n"
<> ", module Application.Helper.Controller\n"
<> ", module IHP.ControllerPrelude\n"
<> ", module Generated.Types\n"
<> ")\n"
<> "where\n\n"
<> "import " <> applicationName <> ".Types\n"
<> "import Application.Helper.Controller\n"
<> "import IHP.ControllerPrelude\n"
<> "import Generated.Types\n"
<> "import " <> applicationName <> ".Routes\n"
viewLayoutHs =
"module " <> applicationName <> ".View.Layout (defaultLayout, Html) where\n"
<> "\n"
<> "import IHP.ViewPrelude\n"
<> "import IHP.Environment\n"
<> "import Generated.Types\n"
<> "import IHP.Controller.RequestContext\n"
<> "import " <> applicationName <> ".Types\n"
<> "import " <> applicationName <> ".Routes\n"
<> "import Application.Helper.View\n"
<> "\n"
<> "defaultLayout :: Html -> Html\n"
<> "defaultLayout inner = [hsx|\n"
<> "<!DOCTYPE html>\n"
<> "<html lang=\"en\">\n"
<> " <head>\n"
<> " {metaTags}\n"
<> "\n"
<> " {stylesheets}\n"
<> " {scripts}\n"
<> "\n"
<> " <title>{pageTitleOrDefault \"App\"}</title>\n"
<> " </head>\n"
<> " <body>\n"
<> " <div class=\"container mt-4\">\n"
<> " {renderFlashMessages}\n"
<> " {inner}\n"
<> " </div>\n"
<> " </body>\n"
<> "</html>\n"
<> "|]\n"
<> "\n"
<> "-- The 'assetPath' function used below appends a `?v=SOME_VERSION` to the static assets in production\n"
<> "-- This is useful to avoid users having old CSS and JS files in their browser cache once a new version is deployed\n"
<> "-- See https://ihp.digitallyinduced.com/Guide/assets.html for more details\n"
<> "\n"
<> "stylesheets :: Html\n"
<> "stylesheets = [hsx|\n"
<> " <link rel=\"stylesheet\" href={assetPath \"/vendor/bootstrap-5.2.1/bootstrap.min.css\"}/>\n"
<> " <link rel=\"stylesheet\" href={assetPath \"/vendor/flatpickr.min.css\"}/>\n"
<> " <link rel=\"stylesheet\" href={assetPath \"/app.css\"}/>\n"
<> " |]\n"
<> "\n"
<> "scripts :: Html\n"
<> "scripts = [hsx|\n"
<> " {when isDevelopment devScripts}\n"
<> " <script src={assetPath \"/vendor/jquery-3.6.0.slim.min.js\"}></script>\n"
<> " <script src={assetPath \"/vendor/timeago.js\"}></script>\n"
<> " <script src={assetPath \"/vendor/popper-2.11.6.min.js\"}></script>\n"
<> " <script src={assetPath \"/vendor/bootstrap-5.2.1/bootstrap.min.js\"}></script>\n"
<> " <script src={assetPath \"/vendor/flatpickr.js\"}></script>\n"
<> " <script src={assetPath \"/vendor/morphdom-umd.min.js\"}></script>\n"
<> " <script src={assetPath \"/vendor/turbolinks.js\"}></script>\n"
<> " <script src={assetPath \"/vendor/turbolinksInstantClick.js\"}></script>\n"
<> " <script src={assetPath \"/vendor/turbolinksMorphdom.js\"}></script>\n"
<> " <script src={assetPath \"/helpers.js\"}></script>\n"
<> " <script src={assetPath \"/ihp-auto-refresh.js\"}></script>\n"
<> " <script src={assetPath \"/app.js\"}></script>\n"
<> " |]\n"
<> "\n"
<> "devScripts :: Html\n"
<> "devScripts = [hsx|\n"
<> " <script id=\"livereload-script\" src={assetPath \"/livereload.js\"} data-ws={liveReloadWebsocketUrl}></script>\n"
<> " |]\n"
<> "\n"
<> "metaTags :: Html\n"
<> "metaTags = [hsx|\n"
<> " <meta charset=\"utf-8\"/>\n"
<> " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\"/>\n"
<> " <meta property=\"og:title\" content=\"App\"/>\n"
<> " <meta property=\"og:type\" content=\"website\"/>\n"
<> " <meta property=\"og:url\" content=\"TODO\"/>\n"
<> " <meta property=\"og:description\" content=\"TODO\"/>\n"
<> " {autoRefreshMeta}\n"
<> "|]\n"
viewPreludeHs =
"module " <> applicationName <> ".View.Prelude\n"
<> "( module IHP.ViewPrelude\n"
<> ", module " <> applicationName <> ".View.Layout\n"
<> ", module Generated.Types\n"
<> ", module " <> applicationName <> ".Types\n"
<> ", module Application.Helper.View\n"
<> ") where\n"
<> "\n"
<> "import IHP.ViewPrelude\n"
<> "import " <> applicationName <> ".View.Layout\n"
<> "import Generated.Types\n"
<> "import " <> applicationName <> ".Types\n"
<> "import " <> applicationName <> ".Routes ()\n"
<> "import Application.Helper.View\n"
welcomeControllerStaticHs =
"module " <> applicationName <> ".Controller.Static where\n"
<> "import " <> applicationName <>".Controller.Prelude\n"
<> "import " <> applicationName <>".View.Static.Welcome\n"
<> "\n"
<> "instance Controller StaticController where\n"
<> " action WelcomeAction = render WelcomeView\n"
welcomeViewStaticHs =
"module " <> applicationName <> ".View.Static.Welcome where\n"
<>"import " <> applicationName <> ".View.Prelude\n"
<>"\n"
<>"data WelcomeView = WelcomeView\n"
<>"\n"
<>"instance View WelcomeView where\n"
<>" html WelcomeView = [hsx|\n"
<>" <div style=\"background-color: #657b83; padding: 2rem; color:hsla(196, 13%, 96%, 1); border-radius: 4px\">\n"
<>" <div style=\"max-width: 800px; margin-left: auto; margin-right: auto\">\n"
<>" <h1 style=\"margin-bottom: 2rem; font-size: 2rem; font-weight: 300; border-bottom: 1px solid white; padding-bottom: 0.25rem; border-color: hsla(196, 13%, 60%, 1)\">\n"
<>" IHP\n"
<>" </h1>\n"
<>"\n"
<>" <h2 style=\"margin-top: 0; margin-bottom: 0rem; font-weight: 900; font-size: 3rem\">\n"
<>" It's working!\n"
<>" </h2>\n"
<>"\n"
<>" <p style=\"margin-top: 1rem; font-size: 1.75rem; font-weight: 600; color:hsla(196, 13%, 80%, 1)\">\n"
<>" Your new application is up and running.\n"
<>" </p>\n"
<>"\n"
<>" <p>\n"
<>" <a\n"
<>" href=\"https://ihp.digitallyinduced.com/Slack\"\n"
<>" style=\"margin-top: 2rem; background-color: #268bd2; padding: 1rem; border-radius: 3px; color: hsla(205, 69%, 98%, 1); text-decoration: none; font-weight: bold; display: inline-block; box-shadow: 0 4px 6px hsla(205, 69%, 0%, 0.08); transition: box-shadow 0.2s; transition: transform 0.2s;\"\n"
<>" target=\"_blank\"\n"
<>" >Join our community on Slack!</a>\n"
<>" </p>\n"
<>"\n"
<>" <a href=\"https://ihp.digitallyinduced.com/Guide/your-first-project.html\" style=\"margin-top: 2rem; background-color: #268bd2; padding: 1rem; border-radius: 3px; color: hsla(205, 69%, 98%, 1); text-decoration: none; font-weight: bold; display: inline-block; box-shadow: 0 4px 6px hsla(205, 69%, 0%, 0.08); transition: box-shadow 0.2s; transition: transform 0.2s;\" target=\"_blank\">\n"
<>" Learn the Next Steps in the Documentation\n"
<>" </a>\n"
<>" </div>\n"
<>" </div>\n"
<>"\n"
<>" <div style=\"max-width: 800px; margin-left: auto; margin-right: auto; margin-top: 4rem\">\n"
<>" <img src=\"/ihp-welcome-icon.svg\" alt=\"/ihp-welcome-icon\" style=\"width:100%;\">\n"
<>" <p style=\"color: hsla(196, 13%, 50%, 1); margin-top: 4rem\">\n"
<>" You can modify this start page by making changes to \"./Web/View/Static/Welcome.hs\".\n"
<>" </p>\n"
<>" </div> \n"
<>"|]"
in
[ EnsureDirectory { directory = applicationName }
, EnsureDirectory { directory = applicationName <> "/Controller" }
, EnsureDirectory { directory = applicationName <> "/View" }
, EnsureDirectory { directory = applicationName <> "/View/Static" }
, AddImport { filePath = "Main.hs", fileContent = "import " <> applicationName <> ".FrontController" }
, AddImport { filePath = "Main.hs", fileContent = "import " <> applicationName <> ".Types" }
, AddMountToFrontController { filePath = "Main.hs", applicationName = applicationName }
, CreateFile { filePath = applicationName <> "/Types.hs", fileContent = typesHs }
, CreateFile { filePath = applicationName <> "/Routes.hs", fileContent = routesHs }
, CreateFile { filePath = applicationName <> "/FrontController.hs", fileContent = frontControllerHs }
, CreateFile { filePath = applicationName <> "/Controller/Prelude.hs", fileContent = controllerPreludeHs }
, CreateFile { filePath = applicationName <> "/View/Layout.hs", fileContent = viewLayoutHs }
, CreateFile { filePath = applicationName <> "/View/Prelude.hs", fileContent = viewPreludeHs }
, CreateFile { filePath = applicationName <> "/Controller/Static.hs", fileContent = welcomeControllerStaticHs }
, CreateFile { filePath = applicationName <> "/View/Static/Welcome.hs", fileContent = welcomeViewStaticHs }
]