diff options
Diffstat (limited to 'Omni/Jr')
| -rw-r--r-- | Omni/Jr/Web.hs | 46 | ||||
| -rw-r--r-- | Omni/Jr/Web/Style.hs | 29 |
2 files changed, 67 insertions, 8 deletions
diff --git a/Omni/Jr/Web.hs b/Omni/Jr/Web.hs index 49c9ad6..6c30be3 100644 --- a/Omni/Jr/Web.hs +++ b/Omni/Jr/Web.hs @@ -58,6 +58,7 @@ type API = :> Get '[Lucid.HTML] TaskListPage :<|> "tasks" :> Capture "id" Text :> Get '[Lucid.HTML] TaskDetailPage :<|> "tasks" :> Capture "id" Text :> "status" :> ReqBody '[FormUrlEncoded] StatusForm :> PostRedirect + :<|> "tasks" :> Capture "id" Text :> "description" :> ReqBody '[FormUrlEncoded] DescriptionForm :> PostRedirect :<|> "tasks" :> Capture "id" Text :> "review" :> Get '[Lucid.HTML] TaskReviewPage :<|> "tasks" :> Capture "id" Text :> "accept" :> PostRedirect :<|> "tasks" :> Capture "id" Text :> "reject" :> ReqBody '[FormUrlEncoded] RejectForm :> PostRedirect @@ -109,6 +110,13 @@ instance FromForm StatusForm where Just s -> Right (StatusForm s) Nothing -> Left "Invalid status" +newtype DescriptionForm = DescriptionForm Text + +instance FromForm DescriptionForm where + fromForm form = do + desc <- parseUnique "description" form + Right (DescriptionForm desc) + pageHead :: (Monad m) => Text -> Lucid.HtmlT m () pageHead title = Lucid.head_ <| do @@ -377,15 +385,30 @@ instance Lucid.ToHtml TaskDetailPage where Lucid.ul_ [Lucid.class_ "dep-list"] <| do traverse_ renderDependency deps - case TaskCore.taskDescription task of - Nothing -> pure () - Just desc -> + case TaskCore.taskType task of + TaskCore.Epic -> do Lucid.div_ [Lucid.class_ "detail-section"] <| do - case TaskCore.taskType task of - TaskCore.Epic -> do - Lucid.h3_ "Design" - Lucid.div_ [Lucid.class_ "markdown-content"] (renderMarkdown desc) - _ -> do + Lucid.h3_ "Design" + case TaskCore.taskDescription task of + Nothing -> Lucid.p_ [Lucid.class_ "empty-msg"] "No design document yet." + Just desc -> Lucid.div_ [Lucid.class_ "markdown-content"] (renderMarkdown desc) + Lucid.details_ [Lucid.class_ "edit-description"] <| do + Lucid.summary_ "Edit Design" + Lucid.form_ [Lucid.method_ "POST", Lucid.action_ ("/tasks/" <> TaskCore.taskId task <> "/description")] <| do + Lucid.textarea_ + [ Lucid.name_ "description", + Lucid.class_ "description-textarea", + Lucid.rows_ "15", + Lucid.placeholder_ "Enter design in Markdown format..." + ] + (Lucid.toHtml (fromMaybe "" (TaskCore.taskDescription task))) + Lucid.div_ [Lucid.class_ "form-actions"] <| do + Lucid.button_ [Lucid.type_ "submit", Lucid.class_ "submit-btn"] "Save Design" + _ -> + case TaskCore.taskDescription task of + Nothing -> pure () + Just desc -> + Lucid.div_ [Lucid.class_ "detail-section"] <| do Lucid.h3_ "Description" Lucid.pre_ [Lucid.class_ "description"] (Lucid.toHtml desc) @@ -790,6 +813,7 @@ server = :<|> taskListHandler :<|> taskDetailHandler :<|> taskStatusHandler + :<|> taskDescriptionHandler :<|> taskReviewHandler :<|> taskAcceptHandler :<|> taskRejectHandler @@ -884,6 +908,12 @@ server = liftIO <| TaskCore.updateTaskStatus tid newStatus [] pure <| addHeader ("/tasks/" <> tid) NoContent + taskDescriptionHandler :: Text -> DescriptionForm -> Servant.Handler (Headers '[Header "Location" Text] NoContent) + taskDescriptionHandler tid (DescriptionForm desc) = do + let descMaybe = if Text.null (Text.strip desc) then Nothing else Just desc + _ <- liftIO <| TaskCore.editTask tid (\t -> t {TaskCore.taskDescription = descMaybe}) + pure <| addHeader ("/tasks/" <> tid) NoContent + taskReviewHandler :: Text -> Servant.Handler TaskReviewPage taskReviewHandler tid = do tasks <- liftIO TaskCore.loadTasks diff --git a/Omni/Jr/Web/Style.hs b/Omni/Jr/Web/Style.hs index d544e25..dbe1daa 100644 --- a/Omni/Jr/Web/Style.hs +++ b/Omni/Jr/Web/Style.hs @@ -473,6 +473,29 @@ formStyles = do borderRadius (px 2) (px 2) (px 2) (px 2) fontSize (px 13) Stylesheet.key "resize" ("vertical" :: Text) + ".edit-description" ? do + marginTop (px 8) + padding (px 8) (px 0) (px 0) (px 0) + borderTop (px 1) solid "#e5e7eb" + (".edit-description" |> "summary") ? do + cursor pointer + color "#0066cc" + fontSize (px 13) + fontWeight (weight 500) + (".edit-description" |> "summary") # hover ? textDecoration underline + ".description-textarea" ? do + width (pct 100) + minHeight (px 250) + padding (px 8) (px 10) (px 8) (px 10) + border (px 1) solid "#d1d5db" + borderRadius (px 2) (px 2) (px 2) (px 2) + fontSize (px 13) + fontFamily ["SF Mono", "Monaco", "Consolas", "monospace"] [monospace] + lineHeight (em 1.5) + Stylesheet.key "resize" ("vertical" :: Text) + marginTop (px 8) + ".form-actions" ? do + marginTop (px 8) activityTimelineStyles :: Css activityTimelineStyles = do @@ -733,6 +756,12 @@ darkModeStyles = ".md-inline-code" ? do backgroundColor "#374151" color "#f3f4f6" + ".edit-description" ? borderTopColor "#374151" + (".edit-description" |> "summary") ? color "#60a5fa" + ".description-textarea" ? do + backgroundColor "#374151" + borderColor "#4b5563" + color "#f3f4f6" prefersDark :: Stylesheet.Feature prefersDark = |
