diff --git a/src/UI/Page.elm b/src/UI/Page.elm new file mode 100644 index 0000000..7d0183f --- /dev/null +++ b/src/UI/Page.elm @@ -0,0 +1,71 @@ +module UI.Page exposing (..) + +import Html exposing (Html, div, header, section) +import Html.Attributes exposing (class, classList) +import UI.AppHeader as AppHeader exposing (AppHeader) +import UI.Sidebar as Sidebar + + +type Hero msg + = Hero (Html msg) + + +type PageContent msg + = PageContent (List (Html msg)) + + +type Page msg + = HeroLayout + { header : AppHeader msg + , hero : Hero msg + , content : + PageContent msg + } + | SidebarLayout + { header : AppHeader msg + , sidebar : List (Html msg) + , sidebarToggled : Bool + , content : PageContent msg + } + | FullLayout { header : AppHeader msg, content : PageContent msg } + + + +-- VIEW + + +viewHero : Hero msg -> Html msg +viewHero (Hero content) = + header [ class "page-hero" ] [ content ] + + +viewContent : PageContent msg -> Html msg +viewContent (PageContent content) = + section [ class "page-content" ] content + + +view : Page msg -> Html msg +view page = + case page of + HeroLayout { header, hero, content } -> + div [ class "page hero-layout" ] + [ AppHeader.view header + , viewHero hero + , viewContent content + ] + + SidebarLayout { header, sidebar, sidebarToggled, content } -> + div + [ class "page sidebar-layout" + , classList [ ( "sidebar-toggled", sidebarToggled ) ] + ] + [ AppHeader.view header + , Sidebar.view sidebar + , viewContent content + ] + + FullLayout { header, content } -> + div [ class "page full-layout" ] + [ AppHeader.view header + , viewContent content + ] diff --git a/src/UnisonLocal/App.elm b/src/UnisonLocal/App.elm index ac2e655..2faa20f 100644 --- a/src/UnisonLocal/App.elm +++ b/src/UnisonLocal/App.elm @@ -27,6 +27,7 @@ import UI.Button as Button import UI.Click as Click exposing (Click(..)) import UI.Icon as Icon import UI.Modal as Modal +import UI.Page as Page import UI.Sidebar as Sidebar import UI.Tooltip as Tooltip import Url exposing (Url) @@ -471,7 +472,7 @@ appTitle clickMsg = appTitle_ (h1 [] [ text "Unison", span [ class "context unison-local" ] [ text "Local" ] ]) -viewAppHeader : Model -> Html Msg +viewAppHeader : Model -> AppHeader.AppHeader Msg viewAppHeader model = let changePerspectiveMsg = @@ -485,12 +486,11 @@ viewAppHeader model = appTitle_ = appTitle (Just changePerspectiveMsg) in - AppHeader.view - { menuToggle = Just ToggleSidebar - , appTitle = appTitle_ - , banner = Nothing - , rightButton = Just (Button.button (ShowModal PublishModal) "Publish on Unison Share" |> Button.share) - } + { menuToggle = Just ToggleSidebar + , appTitle = appTitle_ + , banner = Nothing + , rightButton = Just (Button.button (ShowModal PublishModal) "Publish on Unison Share" |> Button.share) + } viewSidebarHeader : Env -> Html Msg @@ -558,42 +558,41 @@ unisonSubmenu = |> Tooltip.view -viewMainSidebar : Model -> Html Msg +viewMainSidebar : Model -> List (Html Msg) viewMainSidebar model = - Sidebar.view - [ viewMainSidebarCollapseButton model - , div [ class "expanded-content" ] - [ viewSidebarHeader model.env - , div [ class "sidebar-scroll-area" ] - [ Sidebar.section - "Namespaces and Definitions" - [ Html.map CodebaseTreeMsg (CodebaseTree.view model.codebaseTree) ] - , nav [] - (List.map - (\( l, c ) -> Click.view [] [ text l ] c) - subMenu - ++ [ a [ class "show-keyboard-shortcuts", onClick (ShowModal HelpModal) ] - [ text "Keyboard Shortcuts" - , KeyboardShortcut.view model.keyboardShortcut (KeyboardShortcut.single QuestionMark) - ] - ] - ) - ] - ] - , div [ class "collapsed-content" ] - [ unisonSubmenu - , Tooltip.tooltip - (a - [ class "show-keyboard-shortcuts-collapsed", onClick (ShowModal HelpModal) ] - [ KeyboardShortcut.view model.keyboardShortcut (KeyboardShortcut.single QuestionMark) - ] + [ viewMainSidebarCollapseButton model + , div [ class "expanded-content" ] + [ viewSidebarHeader model.env + , div [ class "sidebar-scroll-area" ] + [ Sidebar.section + "Namespaces and Definitions" + [ Html.map CodebaseTreeMsg (CodebaseTree.view model.codebaseTree) ] + , nav [] + (List.map + (\( l, c ) -> Click.view [] [ text l ] c) + subMenu + ++ [ a [ class "show-keyboard-shortcuts", onClick (ShowModal HelpModal) ] + [ text "Keyboard Shortcuts" + , KeyboardShortcut.view model.keyboardShortcut (KeyboardShortcut.single QuestionMark) + ] + ] ) - (Tooltip.Text "Keyboard Shortcuts") - |> Tooltip.withPosition Tooltip.RightOf - |> Tooltip.withArrow Tooltip.Middle - |> Tooltip.view ] ] + , div [ class "collapsed-content" ] + [ unisonSubmenu + , Tooltip.tooltip + (a + [ class "show-help-collapsed", onClick (ShowModal HelpModal) ] + [ KeyboardShortcut.view model.keyboardShortcut (KeyboardShortcut.single QuestionMark) + ] + ) + (Tooltip.Text "Keyboard Shortcuts") + |> Tooltip.withPosition Tooltip.RightOf + |> Tooltip.withArrow Tooltip.Middle + |> Tooltip.view + ] + ] viewHelpModal : OperatingSystem -> KeyboardShortcut.Model -> Html Msg @@ -748,30 +747,39 @@ viewModal model = viewAppLoading : Html msg viewAppLoading = - div [ id "app" ] - [ AppHeader.view (AppHeader.appHeader (appTitle Nothing)) - , Sidebar.view [] - , div [ id "main-content" ] [] - ] + Page.view + (Page.SidebarLayout + { header = AppHeader.appHeader (appTitle Nothing) + , sidebar = [] + , sidebarToggled = False + , content = Page.PageContent [] + } + ) viewAppError : Http.Error -> Html msg viewAppError error = - div [ id "app" ] - [ AppHeader.view (AppHeader.appHeader (appTitle Nothing)) - , Sidebar.view [] - , div [ id "main-content", class "app-error" ] - [ Icon.view Icon.warn - , p [ title (Api.errorToString error) ] - [ text "Unison Local could not be started." ] - ] - ] + Page.view + (Page.SidebarLayout + { header = AppHeader.appHeader (appTitle Nothing) + , sidebar = [] + , sidebarToggled = False + , content = + Page.PageContent + [ div [ class "app-error" ] + [ Icon.view Icon.warn + , p [ title (Api.errorToString error) ] + [ text "Unison Local could not be started." ] + ] + ] + } + ) view : Model -> Browser.Document Msg view model = let - page = + pageContent = case model.route of Route.Perspective _ -> Html.map PerspectiveLandingMsg @@ -782,14 +790,15 @@ view model = Route.Definition _ _ -> Html.map WorkspaceMsg (Workspace.view model.workspace) + + page = + Page.SidebarLayout + { header = viewAppHeader model + , sidebar = viewMainSidebar model + , sidebarToggled = model.sidebarToggled + , content = Page.PageContent [ pageContent ] + } in { title = "Unison Local" - , body = - [ div [ id "app", classList [ ( "sidebar-toggled", model.sidebarToggled ) ] ] - [ viewAppHeader model - , viewMainSidebar model - , div [ id "main-content" ] [ page ] - , viewModal model - ] - ] + , body = [ div [ id "app" ] [ Page.view page, viewModal model ] ] } diff --git a/src/UnisonShare/App.elm b/src/UnisonShare/App.elm index ac92443..61902dc 100644 --- a/src/UnisonShare/App.elm +++ b/src/UnisonShare/App.elm @@ -25,6 +25,7 @@ import UI.Banner as Banner import UI.Button as Button import UI.Click as Click exposing (Click(..)) import UI.Icon as Icon +import UI.Page as Page import UI.Sidebar as Sidebar import UI.Tooltip as Tooltip import UnisonShare.AppModal as AppModal @@ -457,7 +458,7 @@ appTitle clickMsg = appTitle_ (h1 [] [ text "Unison", span [ class "context unison-share" ] [ text "Share" ] ]) -viewAppHeader : Model -> Html Msg +viewAppHeader : Model -> AppHeader.AppHeader Msg viewAppHeader model = let changePerspectiveMsg = @@ -479,12 +480,11 @@ viewAppHeader model = "Check it out!" ) in - AppHeader.view - { menuToggle = Just ToggleSidebar - , appTitle = appTitle_ - , banner = banner - , rightButton = Just (Button.button (ShowModal AppModal.PublishModal) "Publish on Unison Share" |> Button.share) - } + { menuToggle = Just ToggleSidebar + , appTitle = appTitle_ + , banner = banner + , rightButton = Just (Button.button (ShowModal AppModal.PublishModal) "Publish on Unison Share" |> Button.share) + } viewSidebarHeader : Env -> Html Msg @@ -559,7 +559,7 @@ unisonSubmenu = |> Tooltip.view -viewMainSidebar : Model -> Html Msg +viewMainSidebar : Model -> List (Html Msg) viewMainSidebar model = let perspective = @@ -575,69 +575,73 @@ viewMainSidebar model = else UI.nothing in - Sidebar.view - [ viewMainSidebarCollapseButton model - , div [ class "expanded-content" ] - [ viewSidebarHeader model.env - , div [ class "sidebar-scroll-area" ] - [ sidebarContent - , Sidebar.section - "Namespaces and Definitions" - [ Html.map CodebaseTreeMsg (CodebaseTree.view model.codebaseTree) ] - , nav [] - (List.map - (\( l, c ) -> Click.view [] [ text l ] c) - subMenu - ++ [ a [ class "show-keyboard-shortcuts", onClick (ShowModal AppModal.KeyboardShortcutsModal) ] - [ text "Keyboard Shortcuts" - , KeyboardShortcut.view model.keyboardShortcut (KeyboardShortcut.single QuestionMark) - ] - ] - ) - ] - ] - , div [ class "collapsed-content" ] - [ unisonSubmenu - , Tooltip.tooltip - (a - [ class "show-keyboard-shortcuts-collapsed", onClick (ShowModal AppModal.KeyboardShortcutsModal) ] - [ KeyboardShortcut.view model.keyboardShortcut (KeyboardShortcut.single QuestionMark) - ] + [ viewMainSidebarCollapseButton model + , div [ class "expanded-content" ] + [ viewSidebarHeader model.env + , div [ class "sidebar-scroll-area" ] + [ sidebarContent + , Sidebar.section + "Namespaces and Definitions" + [ Html.map CodebaseTreeMsg (CodebaseTree.view model.codebaseTree) ] + , nav [] + (List.map + (\( l, c ) -> Click.view [] [ text l ] c) + subMenu + ++ [ a [ class "show-keyboard-shortcuts", onClick (ShowModal AppModal.KeyboardShortcutsModal) ] + [ text "Keyboard Shortcuts" + , KeyboardShortcut.view model.keyboardShortcut (KeyboardShortcut.single QuestionMark) + ] + ] ) - (Tooltip.Text "Keyboard Shortcuts") - |> Tooltip.withPosition Tooltip.RightOf - |> Tooltip.withArrow Tooltip.Middle - |> Tooltip.view ] ] + , div [ class "collapsed-content" ] + [ unisonSubmenu + , Tooltip.tooltip + (a + [ class "show-help-collapsed", onClick (ShowModal AppModal.KeyboardShortcutsModal) ] + [ KeyboardShortcut.view model.keyboardShortcut (KeyboardShortcut.single QuestionMark) + ] + ) + (Tooltip.Text "Keyboard Shortcuts") + |> Tooltip.withPosition Tooltip.RightOf + |> Tooltip.withArrow Tooltip.Middle + |> Tooltip.view + ] + ] viewAppLoading : Html msg viewAppLoading = - div [ id "app" ] - [ AppHeader.view (AppHeader.appHeader (appTitle Nothing)) - , Sidebar.view [] - , div [ id "main-content" ] [] - ] + Page.view + (Page.FullLayout + { header = AppHeader.appHeader (appTitle Nothing) + , content = Page.PageContent [] + } + ) viewAppError : Http.Error -> Html msg viewAppError error = - div [ id "app" ] - [ AppHeader.view (AppHeader.appHeader (appTitle Nothing)) - , Sidebar.view [] - , div [ id "main-content", class "app-error" ] - [ Icon.view Icon.warn - , p [ title (Api.errorToString error) ] - [ text "Unison Share could not be started." ] - ] - ] + Page.view + (Page.FullLayout + { header = AppHeader.appHeader (appTitle Nothing) + , content = + Page.PageContent + [ div [ class "app-error" ] + [ Icon.view Icon.warn + , p [ title (Api.errorToString error) ] + [ text "Unison Share could not be started." ] + ] + ] + } + ) view : Model -> Browser.Document Msg view model = let - page = + pageContent = case model.route of Route.Perspective _ -> Html.map PerspectiveLandingMsg @@ -648,13 +652,19 @@ view model = Route.Definition _ _ -> Html.map WorkspaceMsg (Workspace.view model.workspace) + + page = + Page.SidebarLayout + { header = viewAppHeader model + , sidebar = viewMainSidebar model + , sidebarToggled = model.sidebarToggled + , content = Page.PageContent [ pageContent ] + } in { title = "Unison Share" , body = - [ div [ id "app", classList [ ( "sidebar-toggled", model.sidebarToggled ) ] ] - [ viewAppHeader model - , viewMainSidebar model - , div [ id "main-content" ] [ page ] + [ div [ id "app" ] + [ Page.view page , Html.map AppModalMsg (AppModal.view model.env model.appModal) ] ] diff --git a/src/css/app.css b/src/css/app.css index fc0b60c..081685e 100644 --- a/src/css/app.css +++ b/src/css/app.css @@ -1,16 +1,5 @@ /* -- Application ---------------------------------------------------------- */ -#app { - display: grid; - grid-template-rows: var(--app-header-height) auto; - grid-template-columns: var(--main-sidebar-width) auto; - grid-template-areas: - "app-header app-header" - "main-sidebar main-content"; - transition: grid-template-columns var(--transition-sidebar-collapse-time); - --transition-sidebar-collapse-time: 0.3s; -} - #app .app-error { display: flex; flex: 1; @@ -347,54 +336,30 @@ color: var(--color-sidebar-keyboard-shortcut-hover-key-fg); } -/* -- Main Content --------------------------------------------------------- */ - -#main-content { - grid-area: main-content; - height: calc(100vh - var(--app-header-height)); - overflow: auto; - scroll-behavior: smooth; - scrollbar-width: auto; - scrollbar-color: var(--color-main-subtle-fg) var(--color-main-bg); -} -#main-content::-webkit-scrollbar { - width: 0.5rem; - height: 0.5rem; -} - -#main-content::-webkit-scrollbar-track { - background: var(--color-main-bg); -} - -#main-content::-webkit-scrollbar-thumb { - background-color: var(--color-main-subtle-fg); - border-radius: var(--border-radius-base); -} - /* -- Responsive ----------------------------------------------------------- */ @media only screen and (min-width: 1025px) { - #app.sidebar-toggled { + .page.sidebar-toggled { --main-sidebar-width: var(--main-sidebar-collapsed-width); } - #app.sidebar-toggled .collapse-sidebar-button { + .page.sidebar-toggled .collapse-sidebar-button { animation: collapse-sidebar-button var(--transition-sidebar-collapse-time) ease-in-out; transition: none; animation-fill-mode: forwards; } - #app.sidebar-toggled #main-sidebar { + .page.sidebar-toggled #main-sidebar { overflow: visible; } - #app.sidebar-toggled #main-sidebar .collapsed-content { + .page.sidebar-toggled #main-sidebar .collapsed-content { opacity: 1; transform: translateX(0); } - #app.sidebar-toggled #main-sidebar .expanded-content { + .page.sidebar-toggled #main-sidebar .expanded-content { transition: opacity; transition-duration: var(--transition-sidebar-collapse-time) * 1.1; transition-delay: 0; @@ -402,7 +367,7 @@ overflow: hidden; } - #app.sidebar-toggled .sidebar-scroll-area { + .page.sidebar-toggled .sidebar-scroll-area { overflow: hidden; } } @@ -413,18 +378,18 @@ grid-template-columns: auto auto; grid-template-areas: "app-header app-header" - "main-content main-content"; + "page-content page-content"; } #main-sidebar { display: none; } - #main-content { + .page-content { width: 100vw; } - #app.sidebar-toggled { + .page.sidebar-toggled { grid-template-rows: 3.5rem auto; grid-template-columns: auto auto; grid-template-areas: @@ -432,13 +397,13 @@ "main-sidebar main-sidebar"; } - #app.sidebar-toggled #main-sidebar { + .page.sidebar-toggled #main-sidebar { display: flex; width: 100vw; } - #app.sidebar-toggled .collapse-sidebar-button, - #app.sidebar-toggled #main-content { + .page.sidebar-toggled .collapse-sidebar-button, + .page.sidebar-toggled .page-content { display: none; } } @@ -458,6 +423,8 @@ } } +@import "./page.css"; + @import "./help-modal.css"; @import "./publish-modal.css"; @import "./report-bug-modal.css"; diff --git a/src/css/page.css b/src/css/page.css new file mode 100644 index 0000000..35a5280 --- /dev/null +++ b/src/css/page.css @@ -0,0 +1,34 @@ +.page { + display: grid; + grid-template-rows: var(--app-header-height) auto; + grid-template-columns: var(--main-sidebar-width) auto; + grid-template-areas: + "app-header app-header" + "main-sidebar page-content"; + transition: grid-template-columns var(--transition-sidebar-collapse-time); + --transition-sidebar-collapse-time: 0.3s; +} + +/* -- Main Content --------------------------------------------------------- */ + +.page-content { + grid-area: page-content; + height: calc(100vh - var(--app-header-height)); + overflow: auto; + scroll-behavior: smooth; + scrollbar-width: auto; + scrollbar-color: var(--color-main-subtle-fg) var(--color-main-bg); +} +.page-content::-webkit-scrollbar { + width: 0.5rem; + height: 0.5rem; +} + +.page-content::-webkit-scrollbar-track { + background: var(--color-main-bg); +} + +.page-content::-webkit-scrollbar-thumb { + background-color: var(--color-main-subtle-fg); + border-radius: var(--border-radius-base); +}