From de0883b89832d43c70c12ae132b33cfc35c00e0a Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Tue, 31 Jan 2023 21:26:58 -0500 Subject: [PATCH] Implement collapse panel - Change profile search menu item to "Job Seekers" --- .../Application/wwwroot/style.css | 7 ++ src/JobsJobsJobs/Common/Views.fs | 18 ++--- src/JobsJobsJobs/Home/Views.fs | 17 +++-- src/JobsJobsJobs/Listings/Views.fs | 74 ++++++++++--------- src/JobsJobsJobs/Profiles/Views.fs | 6 +- 5 files changed, 68 insertions(+), 54 deletions(-) diff --git a/src/JobsJobsJobs/Application/wwwroot/style.css b/src/JobsJobsJobs/Application/wwwroot/style.css index 8fec34e..225a095 100644 --- a/src/JobsJobsJobs/Application/wwwroot/style.css +++ b/src/JobsJobsJobs/Application/wwwroot/style.css @@ -228,6 +228,13 @@ span.jjj-audio-clip:hover { border: solid 1px lightgray; border-radius: .5rem; } +/* Collapse Panel styling */ +a[data-bs-toggle] { + color: var(--bs-body-color); +} +a[data-bs-toggle]:hover { + text-decoration: none; +} /* Footer styling */ footer { display: flex; diff --git a/src/JobsJobsJobs/Common/Views.fs b/src/JobsJobsJobs/Common/Views.fs index 670d1aa..29afec3 100644 --- a/src/JobsJobsJobs/Common/Views.fs +++ b/src/JobsJobsJobs/Common/Views.fs @@ -100,16 +100,16 @@ let markdownEditor attrs name value editorLabel isHtmx = ] /// Wrap content in a collapsing panel -let collapsePanel header content = +let collapsePanel header isShown content = + let showClass = if isShown then " show" else "" div [ _class "card" ] [ - div [ _class "card-body" ] [ - h6 [ _class "card-title" ] [ - // TODO: toggle collapse - //a [ _href "#"; _class "{ 'cp-c': collapsed, 'cp-o': !collapsed }"; @click.prevent="toggle">{{headerText}} ] - txt header + div [ _class "card-header" ] [ + h6 [ _class "mb-0 card-title" ] [ + a [ _href "#jjjCollapse"; _data "bs-toggle" "collapse"; _roleButton; _ariaControls "#jjjCollapse" + _ariaExpanded (isShown.ToString().ToLowerInvariant ()) ] [ txt header ] ] - yield! content ] + div [ _id "jjjCollapse"; _class $"card-body collapse{showClass}" ] content ] /// "Yes" or "No" based on a boolean value @@ -242,7 +242,7 @@ module Layout = if ctx.IsLoggedOn then navLink "/citizen/dashboard" "view-dashboard-variant" "Dashboard" navLink "/help-wanted" "newspaper-variant-multiple-outline" "Help Wanted!" - navLink "/profile/search" "view-list-outline" "Employment Profiles" + navLink "/profile/search" "view-list-outline" "Job Seekers" navLink "/success-stories" "thumb-up" "Success Stories" div [ _class "separator" ] [] navLink "/citizen/account" "account-edit" "My Account" @@ -252,7 +252,7 @@ module Layout = navLink "/citizen/log-off" "logout-variant" "Log Off" else navLink "/" "home" "Home" - navLink "/profile/search" "view-list-outline" "Employment Profiles" + navLink "/profile/search" "view-list-outline" "Job Seekers" navLink "/citizen/log-on" "login-variant" "Log On" navLink "/how-it-works" "help-circle-outline" "How It Works" ] diff --git a/src/JobsJobsJobs/Home/Views.fs b/src/JobsJobsJobs/Home/Views.fs index 1ccdf7f..b70439f 100644 --- a/src/JobsJobsJobs/Home/Views.fs +++ b/src/JobsJobsJobs/Home/Views.fs @@ -854,14 +854,15 @@ module Help = h5 [] [ txt "Search Criteria" ] p [] [ - txt "The employment profile search form is the same whether there is a user logged on or not; however, " - txt "the results are different. There are three sections to the search form. " - strong [] [ txt "Continent" ]; txt " will select profiles from the selected continent, while " - strong [] [ txt "Seeking Remote Work?" ]; txt " will select profiles based whether the citizen has " - txt "selected remote work in their profile. "; strong [] [ txt "Text Search" ]; txt " will search " - txt "several aspects of the employment profile for matches; it is case-insensitive and will match " - txt "using English stemming rules (ex. searching for “force” will match words like " - txt "“force”, “forced”, or “forcing”)." + txt "The "; span [ linkedPage ] [ txt "Job Seekers" ]; txt " page and its search form is the same " + txt "whether there is a user logged on or not; however, the results are different. There are three " + txt "sections to the search form. "; strong [] [ txt "Continent" ]; txt " will select profiles from " + txt "the selected continent, while "; strong [] [ txt "Seeking Remote Work?" ]; txt " will select " + txt "profiles based whether the citizen has selected remote work in their profile. " + strong [] [ txt "Text Search" ]; txt " will search several aspects of the employment profile for " + txt "matches; it is case-insensitive and will match using English stemming rules (ex. searching for " + txt "“force” will match words like “force”, “forced”, or " + txt "“forcing”)." ] p [] [ txt "If more than one field has a value selected, profiles must match all of those selections to be " diff --git a/src/JobsJobsJobs/Listings/Views.fs b/src/JobsJobsJobs/Listings/Views.fs index b485593..729e534 100644 --- a/src/JobsJobsJobs/Listings/Views.fs +++ b/src/JobsJobsJobs/Listings/Views.fs @@ -9,41 +9,40 @@ open JobsJobsJobs.Listings.Domain /// Job listing edit page let edit (m : EditListingForm) continents isNew isHtmx csrf = - pageWithTitle $"""{if isNew then "Add a" else "Edit"} Job Listing""" [ - form [ _class "row g-3"; _method "POST"; _action "/listing/save" ] [ - antiForgery csrf - input [ _type "hidden"; _name (nameof m.Id); _value m.Id ] - div [ _class "col-12 col-sm-10 col-md-8 col-lg-6" ] [ - textBox [ _type "text"; _maxlength "255"; _autofocus ] (nameof m.Title) m.Title "Title" true - div [ _class "form-text" ] [ - txt "No need to put location here; it will always be show to seekers with continent and region" - ] + form [ _class "row g-3"; _method "POST"; _action "/listing/save" ] [ + antiForgery csrf + input [ _type "hidden"; _name (nameof m.Id); _value m.Id ] + div [ _class "col-12 col-sm-10 col-md-8 col-lg-6" ] [ + textBox [ _type "text"; _maxlength "255"; _autofocus ] (nameof m.Title) m.Title "Title" true + div [ _class "form-text" ] [ + txt "No need to put location here; it will always be show to seekers with continent and region" ] - div [ _class "col-12 col-sm-6 col-md-4" ] [ - continentList [] (nameof m.ContinentId) continents None m.ContinentId true - ] - div [ _class "col-12 col-sm-6 col-md-8" ] [ - textBox [ _type "text"; _maxlength "255" ] (nameof m.Region) m.Region "Region" true - div [ _class "form-text" ] [ txt "Country, state, geographic area, etc." ] - ] - div [ _class "col-12" ] [ - checkBox [] (nameof m.RemoteWork) m.RemoteWork "This opportunity is for remote work" - ] - markdownEditor [ _required ] (nameof m.Text) m.Text "Job Description" isHtmx - div [ _class "col-12 col-md-4" ] [ - textBox [ _type "date" ] (nameof m.NeededBy) m.NeededBy "Needed By" false - ] - div [ _class "col-12" ] [ submitButton "content-save-outline" "Save" ] ] + div [ _class "col-12 col-sm-6 col-md-4" ] [ + continentList [] (nameof m.ContinentId) continents None m.ContinentId true + ] + div [ _class "col-12 col-sm-6 col-md-8" ] [ + textBox [ _type "text"; _maxlength "255" ] (nameof m.Region) m.Region "Region" true + div [ _class "form-text" ] [ txt "Country, state, geographic area, etc." ] + ] + div [ _class "col-12" ] [ + checkBox [] (nameof m.RemoteWork) m.RemoteWork "This opportunity is for remote work" + ] + markdownEditor [ _required ] (nameof m.Text) m.Text "Job Description" isHtmx + div [ _class "col-12 col-md-4" ] [ + textBox [ _type "date" ] (nameof m.NeededBy) m.NeededBy "Needed By" false + ] + div [ _class "col-12" ] [ submitButton "content-save-outline" "Save" ] ] + |> List.singleton + |> pageWithTitle $"""{if isNew then "Add a" else "Edit"} Job Listing""" open System.Net /// Page to expire a job listing let expire (m : ExpireListingForm) (listing : Listing) isHtmx csrf = - pageWithTitle $"Expire Job Listing ({WebUtility.HtmlEncode listing.Title})" [ - p [ _class "fst-italic" ] [ + [ p [ _class "fst-italic" ] [ txt "Expiring this listing will remove it from search results. You will be able to see it via your " txt "“My Job Listings” page, but you will not be able to “un-expire” it." ] @@ -65,14 +64,14 @@ let expire (m : ExpireListingForm) (listing : Listing) isHtmx csrf = ] jsOnLoad "jjj.listing.toggleFromHere()" isHtmx ] + |> pageWithTitle $"Expire Job Listing ({WebUtility.HtmlEncode listing.Title})" /// "My Listings" page let mine (listings : ListingForView list) tz = let active = listings |> List.filter (fun it -> not it.Listing.IsExpired) let expired = listings |> List.filter (fun it -> it.Listing.IsExpired) - pageWithTitle "My Job Listings" [ - p [] [ a [ _href "/listing/new/edit"; _class "btn btn-outline-primary" ] [ txt "Add a New Job Listing" ] ] + [ p [] [ a [ _href "/listing/new/edit"; _class "btn btn-outline-primary" ] [ txt "Add a New Job Listing" ] ] if not (List.isEmpty expired) then h4 [ _class "pb-2" ] [ txt "Active Job Listings" ] if List.isEmpty active then p [ _class "pb-3 fst-italic" ] [ txt "You have no active job listings" ] else @@ -117,6 +116,7 @@ let mine (listings : ListingForView list) tz = |> tbody [] ] ] + |> pageWithTitle "My Job Listings" open NodaTime.Text @@ -125,13 +125,12 @@ let private neededBy dt = (LocalDatePattern.CreateWithCurrentCulture "MMMM d, yyyy").Format dt let search (m : ListingSearchForm) continents (listings : ListingForView list option) = - pageWithTitle "Help Wanted" [ - if Option.isNone listings then + [ if Option.isNone listings then p [] [ txt "Enter relevant criteria to find results, or just click “Search” to see all active job " txt "listings." ] - collapsePanel "Search Criteria" [ + collapsePanel "Search Criteria" (List.isEmpty (defaultArg listings [])) [ form [ _class "container"; _method "GET"; _action "/help-wanted" ] [ input [ _type "hidden"; _name "searched"; _value "true" ] div [ _class "row" ] [ @@ -201,11 +200,12 @@ let search (m : ListingSearchForm) continents (listings : ListingForView list op ] | None -> () ] + |> pageWithTitle "Help Wanted" /// The job listing view page let view (it : ListingForView) = article [] [ - h3 [] [ + h3 [ _class "mb-1" ] [ str it.Listing.Title if it.Listing.IsExpired then span [ _class "jjj-heading-label" ] [ @@ -214,11 +214,17 @@ let view (it : ListingForView) = txt "     "; span [ _class "badge bg-success" ] [ txt "Filled via Jobs, Jobs, Jobs" ] ] ] - h4 [ _class "pb-3 text-muted" ] [ str it.ContinentName; rawText " / "; str it.Listing.Region ] + h4 [ _class "mb-3 text-muted" ] [ + str $"{it.ContinentName} / {it.Listing.Region}" + if it.Listing.IsRemote then + span [ _class "jjj-heading-label" ] [ + txt "     "; span [ _class "badge text-bg-info" ] [ txt "Remote" ] + ] + ] p [] [ match it.Listing.NeededBy with | Some needed -> - strong [] [ em [] [ txt "NEEDED BY "; str ((neededBy needed).ToUpperInvariant ()) ] ]; txt " • " + strong [] [ em [] [ txt "NEEDED BY "; str ((neededBy needed).ToUpperInvariant ()) ] ]; br [] // txt " • " | None -> () txt "Listed by "; strong [ _class "me-4" ] [ str (Citizen.name it.Citizen) ]; br [] span [ _class "ms-3" ] []; yield! contactInfo it.Citizen false diff --git a/src/JobsJobsJobs/Profiles/Views.fs b/src/JobsJobsJobs/Profiles/Views.fs index 94207de..827752c 100644 --- a/src/JobsJobsJobs/Profiles/Views.fs +++ b/src/JobsJobsJobs/Profiles/Views.fs @@ -354,8 +354,8 @@ let editHistory (history : EmploymentHistory list) idx csrf = // ~~~ PROFILE SEARCH ~~~ // /// The search form -let private searchForm (m : ProfileSearchForm) continents = - collapsePanel "Search Criteria" [ +let private searchForm (m : ProfileSearchForm) continents isShown = + collapsePanel "Search Criteria" isShown [ form [ _class "container"; _method "GET"; _action "/profile/search" ] [ input [ _type "hidden"; _name "searched"; _value "true" ] div [ _class "row" ] [ @@ -474,7 +474,7 @@ let search m continents tz (results : ProfileForView list option) isPublic = if isPublic then txt "publicly searchable or viewable " txt "profiles." ] - searchForm m continents + searchForm m continents (List.isEmpty (defaultArg results [])) match results with | Some r when List.isEmpty r -> p [ _class "pt-3" ] [ txt "No results found for the specified criteria" ] | Some r -> if isPublic then yield! publicResults r else privateResults r tz