From 1b48acd66ac473176b77fc106b6123dcdedaed80 Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Mon, 15 Aug 2022 18:05:28 -0400 Subject: [PATCH] Add native font stack to pref page (#38) - Update font verbiage to explain native fonts - Sync/update missing/outdated resources --- .../PrayerTracker.Data.fsproj | 1 - src/PrayerTracker.Tests/Data/EntitiesTests.fs | 6 +- .../PrayerTracker.Tests.fsproj | 2 +- src/PrayerTracker.Tests/UI/ViewModelsTests.fs | 34 +++++++---- src/PrayerTracker.UI/Church.fs | 6 +- src/PrayerTracker.UI/Layout.fs | 3 +- src/PrayerTracker.UI/PrayerRequest.fs | 13 ++--- src/PrayerTracker.UI/Resources/Common.es.resx | 57 ++++++++++++++++++- .../Views/SmallGroup/Preferences.es.resx | 12 ++-- src/PrayerTracker.UI/SmallGroup.fs | 36 ++++++++---- src/PrayerTracker.UI/User.fs | 2 +- src/PrayerTracker.UI/ViewModels.fs | 14 +++-- src/PrayerTracker/Church.fs | 2 +- src/PrayerTracker/Extensions.fs | 32 ++++------- src/PrayerTracker/SmallGroup.fs | 2 +- src/PrayerTracker/wwwroot/css/app.css | 3 +- src/PrayerTracker/wwwroot/js/app.js | 13 +++++ 17 files changed, 159 insertions(+), 79 deletions(-) diff --git a/src/PrayerTracker.Data/PrayerTracker.Data.fsproj b/src/PrayerTracker.Data/PrayerTracker.Data.fsproj index a470e2d..5480031 100644 --- a/src/PrayerTracker.Data/PrayerTracker.Data.fsproj +++ b/src/PrayerTracker.Data/PrayerTracker.Data.fsproj @@ -11,7 +11,6 @@ - diff --git a/src/PrayerTracker.Tests/Data/EntitiesTests.fs b/src/PrayerTracker.Tests/Data/EntitiesTests.fs index 2168d44..e9a59c4 100644 --- a/src/PrayerTracker.Tests/Data/EntitiesTests.fs +++ b/src/PrayerTracker.Tests/Data/EntitiesTests.fs @@ -114,11 +114,11 @@ let listPreferencesTests = Expect.equal mt.DaysToKeepNew 7 "The default days to keep new should have been 7" Expect.equal mt.LongTermUpdateWeeks 4 "The default long term update weeks should have been 4" Expect.equal mt.EmailFromName "PrayerTracker" "The default e-mail from name should have been PrayerTracker" - Expect.equal mt.EmailFromAddress "prayer@djs-consulting.com" - "The default e-mail from address should have been prayer@djs-consulting.com" + Expect.equal mt.EmailFromAddress "prayer@bitbadger.solutions" + "The default e-mail from address should have been prayer@bitbadger.solutions" Expect.equal mt.Fonts "native" "The default list fonts were incorrect" Expect.equal mt.HeadingColor "maroon" "The default heading text color should have been maroon" - Expect.equal mt.LineColor "navy" "The default heding line color should have been navy" + Expect.equal mt.LineColor "navy" "The default heading line color should have been navy" Expect.equal mt.HeadingFontSize 16 "The default heading font size should have been 16" Expect.equal mt.TextFontSize 12 "The default text font size should have been 12" Expect.equal mt.RequestSort SortByDate "The default request sort should have been by date" diff --git a/src/PrayerTracker.Tests/PrayerTracker.Tests.fsproj b/src/PrayerTracker.Tests/PrayerTracker.Tests.fsproj index 13de8a4..469b647 100644 --- a/src/PrayerTracker.Tests/PrayerTracker.Tests.fsproj +++ b/src/PrayerTracker.Tests/PrayerTracker.Tests.fsproj @@ -16,7 +16,7 @@ - + diff --git a/src/PrayerTracker.Tests/UI/ViewModelsTests.fs b/src/PrayerTracker.Tests/UI/ViewModelsTests.fs index 418d3e8..5b08c81 100644 --- a/src/PrayerTracker.Tests/UI/ViewModelsTests.fs +++ b/src/PrayerTracker.Tests/UI/ViewModelsTests.fs @@ -261,7 +261,7 @@ let editMemberTests = [] let editPreferencesTests = testList "EditPreferences" [ - test "fromPreferences succeeds for named colors and private list" { + test "fromPreferences succeeds for native fonts, named colors, and private list" { let prefs = ListPreferences.empty let edit = EditPreferences.fromPreferences prefs Expect.equal edit.ExpireDays prefs.DaysToExpire "The expiration days were not filled correctly" @@ -278,7 +278,8 @@ let editPreferencesTests = Expect.equal edit.LineColor prefs.LineColor "The heading line color was not filled correctly" Expect.equal edit.HeadingColorType "Name" "The heading text color type was not derived correctly" Expect.equal edit.HeadingColor prefs.HeadingColor "The heading text color was not filled correctly" - Expect.equal edit.Fonts prefs.Fonts "The list fonts were not filled correctly" + Expect.isTrue edit.IsNative "The IsNative flag should have been true (default value)" + Expect.isNone edit.Fonts "The list fonts should not exist for native font stack" Expect.equal edit.HeadingFontSize prefs.HeadingFontSize "The heading font size was not filled correctly" Expect.equal edit.ListFontSize prefs.TextFontSize "The list text font size was not filled correctly" Expect.equal edit.TimeZone (TimeZoneId.toString prefs.TimeZoneId) "The time zone was not filled correctly" @@ -310,6 +311,13 @@ let editPreferencesTests = Expect.equal edit.Visibility GroupVisibility.PublicList "The list visibility was not derived correctly" } + test "fromPreferences succeeds for non-native fonts" { + let prefs = { ListPreferences.empty with Fonts = "Arial,sans-serif" } + let edit = EditPreferences.fromPreferences prefs + Expect.isFalse edit.IsNative "The IsNative flag should have been false" + Expect.isSome edit.Fonts "The fonts should have been filled for non-native fonts" + Expect.equal edit.Fonts.Value prefs.Fonts "The fonts were not filled correctly" + } ] [] @@ -529,11 +537,12 @@ let requestListTests = "AsHtml succeeds without header or as-of date", fun reqList -> let htmlList = { reqList with SmallGroup = { reqList.SmallGroup with Name = "Test HTML Group" } } - let html = htmlList.AsHtml _s + let html = htmlList.AsHtml _s + let fonts = reqList.SmallGroup.Preferences.FontStack.Replace ("\"", """) Expect.equal -1 (html.IndexOf "Test HTML Group") "The small group name should not have existed (no header)" let curReqHeading = - [ """""" + [ $"""
""" "" """
""" "    Current Requests   
" @@ -541,16 +550,16 @@ let requestListTests = |> String.concat "" Expect.stringContains html curReqHeading """Heading for category "Current Requests" not found""" let curReqHtml = - [ "
    " - """
  • """ + [ $"""
      """ + """
    • """ "Zeb – zyx
    • " - """
    • """ + """
    • """ "Aaron – abc
    " ] |> String.concat "" Expect.stringContains html curReqHtml """Expected HTML for "Current Requests" requests not found""" let praiseHeading = - [ """""" + [ $"""
    """ "" """
    """ "    Praise Reports   
    " @@ -558,8 +567,8 @@ let requestListTests = |> String.concat "" Expect.stringContains html praiseHeading """Heading for category "Praise Reports" not found""" let praiseHtml = - [ "
      " - """
    • """ + [ $"""
        """ + """
      • """ "nmo
      " ] |> String.concat "" @@ -571,9 +580,10 @@ let requestListTests = SmallGroup = { reqList.SmallGroup with Name = "Test HTML Group" } ShowHeader = true } - let html = htmlList.AsHtml _s + let html = htmlList.AsHtml _s + let fonts = reqList.SmallGroup.Preferences.FontStack.Replace ("\"", """) let lstHeading = - [ """
      """ + [ $"""
      """ """Prayer Requests
      """ """Test HTML Group
      """ htmlList.Date.ToString ("MMMM d, yyyy", null) diff --git a/src/PrayerTracker.UI/Church.fs b/src/PrayerTracker.UI/Church.fs index 2adefb9..de740fc 100644 --- a/src/PrayerTracker.UI/Church.fs +++ b/src/PrayerTracker.UI/Church.fs @@ -41,12 +41,14 @@ let edit (model : EditChurch) ctx viewInfo = div [ _checkboxField ] [ inputField "checkbox" (nameof model.HasInterface) "True" [ if defaultArg model.HasInterface false then _checked ] - label [ _for (nameof model.HasInterface) ] [ locStr s["Has an interface with Virtual Prayer Room"] ] + label [ _for (nameof model.HasInterface) ] [ + locStr s["Has an Interface with “{0}”", "Virtual Prayer Space"] + ] ] ] div [ _fieldRowWith [ "pt-fadeable" ]; _id "divInterfaceAddress" ] [ div [ _inputField ] [ - label [ _for (nameof model.InterfaceAddress) ] [ locStr s["VPR Interface URL"] ] + label [ _for (nameof model.InterfaceAddress) ] [ locStr s["Interface URL"] ] inputField "url" (nameof model.InterfaceAddress) (defaultArg model.InterfaceAddress "") [] ] ] diff --git a/src/PrayerTracker.UI/Layout.fs b/src/PrayerTracker.UI/Layout.fs index a9e6277..42e27f6 100644 --- a/src/PrayerTracker.UI/Layout.fs +++ b/src/PrayerTracker.UI/Layout.fs @@ -302,11 +302,12 @@ let private contentSection viewInfo pgTitle (content : XmlNode) = [ htmlFooter viewInfo match viewInfo.OnLoadScript with | Some onLoad -> + let doCall = if onLoad.EndsWith ")" then "" else "()" script [] [ rawText $""" window.doOnLoad = () => {{ if (window.PT) {{ - {onLoad}() + {onLoad}{doCall} delete window.doOnLoad }} else {{ setTimeout(window.doOnLoad, 500) }} }} diff --git a/src/PrayerTracker.UI/PrayerRequest.fs b/src/PrayerTracker.UI/PrayerRequest.fs index 3823a19..77bac90 100644 --- a/src/PrayerTracker.UI/PrayerRequest.fs +++ b/src/PrayerTracker.UI/PrayerRequest.fs @@ -54,15 +54,10 @@ let edit (model : EditRequest) today ctx viewInfo = div [ _fieldRow ] [ div [ _inputField ] [ label [] [ locStr s["Expiration"] ] - ReferenceList.expirationList s (not model.IsNew) - |> List.map (fun exp -> - let radioId = String.concat "_" [ nameof model.Expiration; fst exp ] - span [ _class "text-nowrap" ] [ - radio (nameof model.Expiration) radioId (fst exp) model.Expiration - label [ _for radioId ] [ space; locStr (snd exp) ] - rawText "     " - ]) - |> div [ _class "pt-center-text" ] + span [ _class "pt-radio-group" ] [ + for code, name in ReferenceList.expirationList s (not model.IsNew) do + label [] [ radio (nameof model.Expiration) "" code model.Expiration; locStr name ] + ] ] ] div [ _fieldRow ] [ diff --git a/src/PrayerTracker.UI/Resources/Common.es.resx b/src/PrayerTracker.UI/Resources/Common.es.resx index a131275..05602d1 100644 --- a/src/PrayerTracker.UI/Resources/Common.es.resx +++ b/src/PrayerTracker.UI/Resources/Common.es.resx @@ -396,8 +396,8 @@ El miembro del grupo “{0}” se eliminó con éxito - - El grupo {0} y sus {1} peticion(es) de oración se ha eliminado correctamente (acceso revocada por {2} usuario(s)) + + El grupo “{0}” y sus {1} peticion(es) de oración se ha eliminado correctamente; acceso revocada por {2} usuario(s) La contraseña antigua es incorrecta - la contraseña NO ha cambiado @@ -742,7 +742,7 @@ Este - d \de MMMM yyyy + d \d\e MMMM yyyy Montaña @@ -831,4 +831,55 @@ Administradores + + Fuentes Nativas + + + Fuentes con Nombre + + + Seleccione una Iglesia + + + Seleccione un Grupo + + + Nombre de Miembro + + + Color Personalizado + + + Nombre de la Iglesia + + + Ciudad + + + Tiene una Interfaz con “{0}” + + + URL de la Interfaz + + + Iglesia “{1}” {0} con éxito + + + La iglesia "{0}" y sus {1} grupo(s) (con {2} peticion(es) de oración) se eliminaron correctamente; acceso revocado de {3} usuario(s) + + + El grupo “{1}” {0} con éxito + + + Primer Nombre + + + Apellido + + + Contraseña otra Vez + + + Este Usuario Es un Administrador de {0} + \ No newline at end of file diff --git a/src/PrayerTracker.UI/Resources/Views/SmallGroup/Preferences.es.resx b/src/PrayerTracker.UI/Resources/Views/SmallGroup/Preferences.es.resx index 08f932e..cb2415b 100644 --- a/src/PrayerTracker.UI/Resources/Views/SmallGroup/Preferences.es.resx +++ b/src/PrayerTracker.UI/Resources/Views/SmallGroup/Preferences.es.resx @@ -117,16 +117,16 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Con la extensión “serif” o el “sans-serif” hará que el navegador del usuario para utilizar el valor predeterminado “serif” de la fuente (“Times New Roman” en Windows) o “sans-serif” de la fuente (“Arial” en Windows) si no otras fuentes en la lista se encuentran. + + Terminar esta lista con “serif” o “sans-serif” hará que el navegador del usuario utilice la fuente predeterminado “serif” (“Times New Roman” en Windows) o “sans-serif” (“Arial” en Windows) si no se encuentran otras fuentes en la lista. Si desea un color personalizado, que puede ser capaz de obtener algunas ideas (y una lista de valores RGB para los colores) de la lista de la Escuela de W3 de <a href="http://www.w3schools.com/html/html_colornames.asp" title="La Lista de Nombres de Colores HTML - La Escuela de W3">nombres de colores HTML</a>. - - Lista de nombres de fuentes separados por comas. + + Las fuentes nativas coinciden con la fuente predeterminada según el dispositivo del usuario (computadora, teléfono, tableta, etc.). - - La primera fuente que se corresponde es el que se utiliza. + + Las fuentes con nombre deben estar separadas por comas y se mostrarán usando la primera que el usuario tenga en la lista. \ No newline at end of file diff --git a/src/PrayerTracker.UI/SmallGroup.fs b/src/PrayerTracker.UI/SmallGroup.fs index 2c58c68..74acb79 100644 --- a/src/PrayerTracker.UI/SmallGroup.fs +++ b/src/PrayerTracker.UI/SmallGroup.fs @@ -30,13 +30,15 @@ let announcement isAdmin ctx viewInfo = div [ _fieldRow ] [ div [ _inputField ] [ label [] [ locStr s["Send Announcement to"]; rawText ":" ] - div [ _class "pt-center-text" ] [ - radio (nameof model.SendToClass) $"{nameof model.SendToClass}_Y" "Y" "Y" - label [ _for $"{nameof model.SendToClass}_Y" ] [ - locStr s["This Group"]; rawText "     " + div [ _class "pt-radio-group" ] [ + label [] [ + radio (nameof model.SendToClass) $"{nameof model.SendToClass}_Y" "Y" "Y" + locStr s["This Group"] + ] + label [] [ + radio (nameof model.SendToClass) $"{nameof model.SendToClass}_N" "N" "Y" + locStr s["All {0} Users", s["PrayerTracker"]] ] - radio (nameof model.SendToClass) $"{nameof model.SendToClass}_N" "N" "Y" - label [ _for $"{nameof model.SendToClass}_N" ] [ locStr s["All {0} Users", s["PrayerTracker"]] ] ] ] ] @@ -519,7 +521,21 @@ let preferences (model : EditPreferences) ctx viewInfo = legend [] [ strong [] [ icon "font_download"; rawText "  "; locStr s["Fonts"] ] ] div [ _inputField ] [ label [ _for (nameof model.Fonts) ] [ locStr s["Fonts** for List"] ] - inputField "text" (nameof model.Fonts) model.Fonts [ _required ] + let value = if model.IsNative then "True" else "False" + span [ _class "pt-radio-group" ] [ + label [] [ + radio (nameof model.IsNative) $"{nameof model.IsNative}_Y" "True" value + locStr s["Native Fonts"] + ] + inputField "text" "nativeFontSpacer" "" [ _style "visibility:hidden" ] + ] + span [ _class "pt-radio-group" ] [ + label [] [ + radio (nameof model.IsNative) $"{nameof model.IsNative}_N" "False" value + locStr s["Named Fonts"] + ] + inputField "text" (nameof model.Fonts) (defaultArg model.Fonts "") [ _required ] + ] ] div [ _fieldRow ] [ div [ _inputField ] [ @@ -595,11 +611,11 @@ let preferences (model : EditPreferences) ctx viewInfo = ] p [] [ rawText "** " - raw l["List font names, separated by commas."] + raw l["Native fonts match the default font based on the user's device (computer, phone, tablet, etc.)."] space - raw l["The first font that is matched is the one that is used."] + raw l["Named fonts should be separated by commas, and will be displayed using the first one the user has in the list."] space - raw l["Ending with either “serif” or “sans-serif” will cause the user's browser to use the default “serif” font (“Times New Roman” on Windows) or “sans-serif” font (“Arial” on Windows) if no other fonts in the list are found."] + raw l["Ending this list with either “serif” or “sans-serif” will cause the user's browser to use the default “serif” font (“Times New Roman” on Windows) or “sans-serif” font (“Arial” on Windows) if no other fonts in the list are found."] ] p [] [ rawText "*** " diff --git a/src/PrayerTracker.UI/User.fs b/src/PrayerTracker.UI/User.fs index a6cc7d0..87783df 100644 --- a/src/PrayerTracker.UI/User.fs +++ b/src/PrayerTracker.UI/User.fs @@ -133,7 +133,7 @@ let edit (model : EditUser) ctx viewInfo = ] div [ _checkboxField ] [ inputField "checkbox" (nameof model.IsAdmin) "True" [ if defaultArg model.IsAdmin false then _checked ] - label [ _for (nameof model.IsAdmin) ] [ locStr s["This user is a PrayerTracker administrator"] ] + label [ _for (nameof model.IsAdmin) ] [ locStr s["This User Is a {0} Administrator", s["PrayerTracker"]] ] ] div [ _fieldRow ] [ submit [] "save" s["Save User"] ] ] diff --git a/src/PrayerTracker.UI/ViewModels.fs b/src/PrayerTracker.UI/ViewModels.fs index 4f9597c..c9d74e2 100644 --- a/src/PrayerTracker.UI/ViewModels.fs +++ b/src/PrayerTracker.UI/ViewModels.fs @@ -374,8 +374,11 @@ type EditPreferences = /// The named color for the heading text HeadingColor : string + /// Whether the class uses the native font stack + IsNative : bool + /// The fonts to use for the list - Fonts : string + Fonts : string option /// The font size for the heading text HeadingFontSize : int @@ -416,7 +419,7 @@ with DefaultEmailType = EmailFormat.fromCode this.DefaultEmailType LineColor = this.LineColor HeadingColor = this.HeadingColor - Fonts = this.Fonts + Fonts = if this.IsNative || Option.isNone this.Fonts then "native" else this.Fonts.Value HeadingFontSize = this.HeadingFontSize TextFontSize = this.ListFontSize TimeZoneId = TimeZoneId this.TimeZone @@ -442,7 +445,8 @@ module EditPreferences = LineColor = prefs.LineColor HeadingColorType = setType prefs.HeadingColor HeadingColor = prefs.HeadingColor - Fonts = prefs.Fonts + IsNative = (prefs.Fonts = "native") + Fonts = if prefs.Fonts = "native" then None else Some prefs.Fonts HeadingFontSize = prefs.HeadingFontSize ListFontSize = prefs.TextFontSize TimeZone = TimeZoneId.toString prefs.TimeZoneId @@ -804,7 +808,7 @@ with reqs |> List.map (fun req -> let bullet = if this.IsNew req then "circle" else "disc" - li [ _style $"list-style-type:{bullet};font-family:{p.FontStack};font-size:%i{p.TextFontSize}pt;padding-bottom:.25em;" ] [ + li [ _style $"list-style-type:{bullet};padding-bottom:.25em;" ] [ match req.Requestor with | Some r when r <> "" -> strong [] [ str r ] @@ -825,7 +829,7 @@ with rawText "  ("; str s["as of"].Value; str " "; str dt; rawText ")" ] ]) - |> ul [] + |> ul [ _style $"font-family:{p.FontStack};font-size:%i{p.TextFontSize}pt" ] br [] ] |> RenderView.AsString.htmlNodes diff --git a/src/PrayerTracker/Church.fs b/src/PrayerTracker/Church.fs index f7847ca..a669853 100644 --- a/src/PrayerTracker/Church.fs +++ b/src/PrayerTracker/Church.fs @@ -24,7 +24,7 @@ let delete chId : HttpHandler = requireAccess [ Admin ] >=> validateCsrf >=> fun let! _, stats = findStats churchId conn do! Churches.deleteById churchId conn addInfo ctx - ctx.Strings["The church {0} and its {1} small groups (with {2} prayer request(s)) were deleted successfully; revoked access from {3} user(s)", + ctx.Strings["The church “{0}” and its {1} small group(s) (with {2} prayer request(s)) were deleted successfully; revoked access from {3} user(s)", church.Name, stats.SmallGroups, stats.PrayerRequests, stats.Users] return! redirectTo false "/churches" next ctx | None -> return! fourOhFour ctx diff --git a/src/PrayerTracker/Extensions.fs b/src/PrayerTracker/Extensions.fs index 8d5c5a9..6f6411d 100644 --- a/src/PrayerTracker/Extensions.fs +++ b/src/PrayerTracker/Extensions.fs @@ -2,7 +2,6 @@ module PrayerTracker.Extensions open Microsoft.AspNetCore.Http -open Microsoft.FSharpLu open Newtonsoft.Json open NodaTime open NodaTime.Serialization.JsonNet @@ -17,18 +16,18 @@ let private jsonSettings = JsonSerializerSettings().ConfigureForNodaTime DateTim type ISession with /// Set an object in the session - member this.SetObject key value = + member this.SetObject<'T> key (value : 'T) = this.SetString (key, JsonConvert.SerializeObject (value, jsonSettings)) /// Get an object from the session - member this.GetObject<'T> key = + member this.TryGetObject<'T> key = match this.GetString key with - | null -> Unchecked.defaultof<'T> - | v -> JsonConvert.DeserializeObject<'T> (v, jsonSettings) + | null -> None + | v -> Some (JsonConvert.DeserializeObject<'T> (v, jsonSettings)) /// The currently logged on small group member this.CurrentGroup - with get () = this.GetObject Key.Session.currentGroup |> Option.fromObject + with get () = this.TryGetObject Key.Session.currentGroup and set (v : SmallGroup option) = match v with | Some group -> this.SetObject Key.Session.currentGroup group @@ -36,7 +35,7 @@ type ISession with /// The currently logged on user member this.CurrentUser - with get () = this.GetObject Key.Session.currentUser |> Option.fromObject + with get () = this.TryGetObject Key.Session.currentUser and set (v : User option) = match v with | Some user -> this.SetObject Key.Session.currentUser { user with PasswordHash = "" } @@ -45,9 +44,8 @@ type ISession with /// Current messages for the session member this.Messages with get () = - match box (this.GetObject Key.Session.userMessages) with - | null -> List.empty - | msgs -> unbox msgs + this.TryGetObject Key.Session.userMessages + |> Option.defaultValue List.empty and set (v : UserMessage list) = this.SetObject Key.Session.userMessages v @@ -69,28 +67,18 @@ type ClaimsPrincipal with else None -open System.Threading.Tasks open Giraffe -open Microsoft.Extensions.Configuration open Npgsql /// Extensions on the ASP.NET Core HTTP context type HttpContext with - // TODO: is this disposed? - member private this.LazyConn : Lazy> = lazy (backgroundTask { - let cfg = this.GetService () - let conn = new NpgsqlConnection (cfg.GetConnectionString "PrayerTracker") - do! conn.OpenAsync () - return conn - }) + /// The system clock (via DI) + member this.Clock = this.GetService () /// The PostgreSQL connection (configured via DI) member this.Conn = this.GetService () - /// The system clock (via DI) - member this.Clock = this.GetService () - /// The current instant member this.Now = this.Clock.GetCurrentInstant () diff --git a/src/PrayerTracker/SmallGroup.fs b/src/PrayerTracker/SmallGroup.fs index 9779148..2b16b32 100644 --- a/src/PrayerTracker/SmallGroup.fs +++ b/src/PrayerTracker/SmallGroup.fs @@ -23,7 +23,7 @@ let delete grpId : HttpHandler = requireAccess [ Admin ] >=> validateCsrf >=> fu let! users = Users.countByGroup groupId conn do! SmallGroups.deleteById groupId conn addInfo ctx - ctx.Strings["The group {0} and its {1} prayer request(s) were deleted successfully; revoked access from {2} user(s)", + ctx.Strings["The group “{0}” and its {1} prayer request(s) were deleted successfully; revoked access from {2} user(s)", grp.Name, reqs, users] return! redirectTo false "/small-groups" next ctx | None -> return! fourOhFour ctx diff --git a/src/PrayerTracker/wwwroot/css/app.css b/src/PrayerTracker/wwwroot/css/app.css index bdac956..080a54e 100644 --- a/src/PrayerTracker/wwwroot/css/app.css +++ b/src/PrayerTracker/wwwroot/css/app.css @@ -257,7 +257,8 @@ footer a:hover { .pt-radio-group { display: flex; flex-flow: row; - gap: 2rem; + gap: 1.5rem; + align-items: baseline; } .pt-center-text { text-align: center; diff --git a/src/PrayerTracker/wwwroot/js/app.js b/src/PrayerTracker/wwwroot/js/app.js index 5244a0b..efd2e43 100644 --- a/src/PrayerTracker/wwwroot/js/app.js +++ b/src/PrayerTracker/wwwroot/js/app.js @@ -243,6 +243,13 @@ this.PT = { } }, + /** + * Enable or disable the font list based on whether the native font stack is selected or not + */ + checkFonts() { + document.getElementById("Fonts").disabled = document.getElementById("IsNative_Y").checked + }, + /** * Bind the event handlers */ @@ -261,6 +268,12 @@ this.PT = { }) PT.smallGroup.preferences.toggleType(name) }) + ;["Y", "N"].map(name => { + document.getElementById(`IsNative_${name}`).addEventListener("click", () => { + PT.smallGroup.preferences.checkFonts() + }) + }) + PT.smallGroup.preferences.checkFonts() }, }, },