Fix request/announcement text (#36)

- Update defaults for small group
- Add support for native font stack (#38)
- Fix color picker error when named color is selected
- Use invariant culture for URL formatting (#41)
This commit is contained in:
Daniel J. Summers 2022-08-14 19:46:37 -04:00
parent ab3f8dcc43
commit ae29a6c03b
9 changed files with 75 additions and 19 deletions

View File

@ -312,6 +312,13 @@ type ListPreferences =
/// How the as-of date should be automatically displayed
AsOfDateDisplay : AsOfDateDisplay
}
with
/// The list of fonts to use when displaying request lists (converts "native" to native font stack)
member this.FontStack =
if this.Fonts = "native" then
"""system-ui,-apple-system,"Segoe UI",Roboto,Ubuntu,"Liberation Sans",Cantarell,"Helvetica Neue",sans-serif"""
else this.Fonts
/// Functions to support list preferences
module ListPreferences =
@ -323,8 +330,8 @@ module ListPreferences =
DaysToKeepNew = 7
LongTermUpdateWeeks = 4
EmailFromName = "PrayerTracker"
EmailFromAddress = "prayer@djs-consulting.com"
Fonts = "Century Gothic,Tahoma,Luxi Sans,sans-serif"
EmailFromAddress = "prayer@bitbadger.solutions"
Fonts = "native"
HeadingColor = "maroon"
LineColor = "navy"
HeadingFontSize = 16

View File

@ -98,6 +98,15 @@ let expirationTests =
[<Tests>]
let listPreferencesTests =
testList "ListPreferences" [
test "FontStack is correct for native fonts" {
Expect.equal ListPreferences.empty.FontStack
"""system-ui,-apple-system,"Segoe UI",Roboto,Ubuntu,"Liberation Sans",Cantarell,"Helvetica Neue",sans-serif"""
"The expected native font stack was incorrect"
}
test "FontStack is correct for specific fonts" {
Expect.equal { ListPreferences.empty with Fonts = "Arial,sans-serif" }.FontStack "Arial,sans-serif"
"The specified fonts were not returned correctly"
}
test "empty is as expected" {
let mt = ListPreferences.empty
Expect.equal mt.SmallGroupId.Value Guid.Empty "The small group ID should have been an empty GUID"
@ -107,7 +116,7 @@ let listPreferencesTests =
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.Fonts "Century Gothic,Tahoma,Luxi Sans,sans-serif" "The default list fonts were incorrect"
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.HeadingFontSize 16 "The default heading font size should have been 16"

View File

@ -78,6 +78,28 @@ let namedColorList name selected attrs (s : IStringLocalizer) =
|> List.ofSeq
|> select (_name name :: attrs)
/// Convert a named color to its hex notation
let colorToHex (color : string) =
match color with
| it when it.StartsWith "#" -> color
| "aqua" -> "#00ffff"
| "black" -> "#000000"
| "blue" -> "#0000ff"
| "fuchsia" -> "#ff00ff"
| "gray" -> "#808080"
| "green" -> "#008000"
| "lime" -> "#00ff00"
| "maroon" -> "#800000"
| "navy" -> "#000080"
| "olive" -> "#808000"
| "purple" -> "#800080"
| "red" -> "#ff0000"
| "silver" -> "#c0c0c0"
| "teal" -> "#008080"
| "white" -> "#ffffff"
| "yellow" -> "#ffff00"
| it -> it
/// Generate an input[type=radio] that is selected if its value is the current value
let radio name domId value current =
input [ _type "radio"

View File

@ -1,6 +1,6 @@
module PrayerTracker.Views.PrayerRequest
open System
open System.Globalization
open System.IO
open Giraffe
open Giraffe.ViewEngine
@ -17,7 +17,11 @@ let edit (model : EditRequest) today ctx viewInfo =
let s = I18N.localizer.Force ()
let pageTitle = if model.IsNew then "Add a New Request" else "Edit Request"
let vi = AppViewInfo.withOnLoadScript "PT.initCKEditor" viewInfo
form [ _action "/prayer-request/save"; _method "post"; _class "pt-center-columns"; Target.content ] [
form [ _action "/prayer-request/save"
_method "post"
_class "pt-center-columns"
_onsubmit "PT.updateCKEditor()"
Target.content ] [
csrfToken ctx
inputField "hidden" (nameof model.RequestId) model.RequestId []
div [ _fieldRow ] [
@ -79,7 +83,7 @@ let email model viewInfo =
let pageTitle = $"""{s["Prayer Requests"].Value} {model.SmallGroup.Name}"""
let prefs = model.SmallGroup.Preferences
let addresses = model.Recipients |> List.map (fun mbr -> $"{mbr.Name} <{mbr.Email}>") |> String.concat ", "
[ p [ _style $"font-family:{prefs.Fonts};font-size:%i{prefs.TextFontSize}pt;" ] [
[ p [ _style $"font-family:{prefs.FontStack};font-size:%i{prefs.TextFontSize}pt;" ] [
locStr s["The request list was sent to the following people, via individual e-mails"]
rawText ":"
br []
@ -202,7 +206,7 @@ let maintain (model : MaintainRequests) (ctx : HttpContext) viewInfo =
]
]
div [ updateClass ] [
str (req.UpdatedDate.ToString(s["MMMM d, yyyy"].Value, Globalization.CultureInfo.CurrentUICulture))
str (req.UpdatedDate.ToString(s["MMMM d, yyyy"].Value, CultureInfo.CurrentUICulture))
]
div [ _class "cell" ] [ locStr types[req.RequestType] ]
div [ expiredClass ] [ str (match req.Requestor with Some r -> r | None -> " ") ]
@ -300,7 +304,7 @@ let print model version =
rawText (model.AsHtml s)
br []
hr []
div [ _style $"font-size:70%%;font-family:{model.SmallGroup.Preferences.Fonts};" ] [
div [ _style $"font-size:70%%;font-family:{model.SmallGroup.Preferences.FontStack};" ] [
img [ _src $"""/img/{s["footer_en"].Value}.png"""
_style "vertical-align:text-bottom;"
_alt imgAlt
@ -317,7 +321,7 @@ let view model viewInfo =
let s = I18N.localizer.Force ()
let pageTitle = $"""{s["Prayer Requests"].Value} {model.SmallGroup.Name}"""
let spacer = rawText " &nbsp; &nbsp; &nbsp; "
let dtString = model.Date.ToString ("yyyy-MM-dd", null) // TODO: this should be invariant
let dtString = model.Date.ToString ("yyyy-MM-dd", CultureInfo.InvariantCulture)
[ div [ _class "pt-center-text" ] [
br []
a [ _class "pt-icon-link"
@ -333,7 +337,7 @@ let view model viewInfo =
if date.DayOfWeek = IsoDayOfWeek.Sunday then date else findSunday (date.PlusDays 1)
let sunday = findSunday model.Date
a [ _class "pt-icon-link"
_href $"""/prayer-requests/view/{sunday.ToString ("yyyy-MM-dd", null)}""" // TODO: make invariant
_href $"""/prayer-requests/view/{sunday.ToString ("yyyy-MM-dd", CultureInfo.InvariantCulture)}"""
_title s["List for Next Sunday"].Value ] [
icon "update"; rawText " &nbsp;"; locStr s["List for Next Sunday"]
]

View File

@ -14,7 +14,11 @@ let announcement isAdmin ctx viewInfo =
let model = { SendToClass = ""; Text = ""; AddToRequestList = None; RequestType = None }
let reqTypes = ReferenceList.requestTypeList s
let vi = AppViewInfo.withOnLoadScript "PT.smallGroup.announcement.onPageLoad" viewInfo
form [ _action "/small-group/announcement/send"; _method "post"; _class "pt-center-columns"; Target.content ] [
form [ _action "/small-group/announcement/send"
_method "post"
_class "pt-center-columns"
_onsubmit "PT.updateCKEditor()"
Target.content ] [
csrfToken ctx
div [ _fieldRow ] [
div [ _inputFieldWith [ "pt-editor" ] ] [
@ -461,7 +465,7 @@ let preferences (model : EditPreferences) ctx viewInfo =
input [ _type "color"
_name (nameof model.LineColor)
_id $"{nameof model.LineColor}_Color"
_value model.LineColor // TODO: convert to hex or skip if named
_value (colorToHex model.LineColor)
if not (model.LineColor.StartsWith "#") then _disabled ]
]
]
@ -483,7 +487,7 @@ let preferences (model : EditPreferences) ctx viewInfo =
input [ _type "color"
_name (nameof model.HeadingColor)
_id $"{nameof model.HeadingColor}_Color"
_value model.HeadingColor // TODO: convert to hex or skip if named
_value (colorToHex model.HeadingColor)
if not (model.HeadingColor.StartsWith "#") then _disabled ]
]
]

View File

@ -778,7 +778,7 @@ with
let p = this.SmallGroup.Preferences
let asOfSize = Math.Round (float p.TextFontSize * 0.8, 2)
[ if this.ShowHeader then
div [ _style $"text-align:center;font-family:{p.Fonts}" ] [
div [ _style $"text-align:center;font-family:{p.FontStack}" ] [
span [ _style $"font-size:%i{p.HeadingFontSize}pt;" ] [
strong [] [ str s["Prayer Requests"].Value ]
]
@ -792,7 +792,7 @@ with
br []
for _, name, reqs in this.RequestsByType s do
div [ _style "padding-left:10px;padding-bottom:.5em;" ] [
table [ _style $"font-family:{p.Fonts};page-break-inside:avoid;" ] [
table [ _style $"font-family:{p.FontStack};page-break-inside:avoid;" ] [
tr [] [
td [ _style $"font-size:%i{p.HeadingFontSize}pt;color:{p.HeadingColor};padding:3px 0;border-top:solid 3px {p.LineColor};border-bottom:solid 3px {p.LineColor};font-weight:bold;" ] [
rawText "&nbsp; &nbsp; "; str name.Value; rawText "&nbsp; &nbsp; "
@ -804,7 +804,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.Fonts};font-size:%i{p.TextFontSize}pt;padding-bottom:.25em;" ] [
li [ _style $"list-style-type:{bullet};font-family:{p.FontStack};font-size:%i{p.TextFontSize}pt;padding-bottom:.25em;" ] [
match req.Requestor with
| Some r when r <> "" ->
strong [] [ str r ]

View File

@ -260,7 +260,7 @@ let sendAnnouncement : HttpHandler = requireAccess [ User ] >=> validateCsrf >=>
// Reformat the text to use the class's font stylings
let requestText = ckEditorToText model.Text
let htmlText =
p [ _style $"font-family:{pref.Fonts};font-size:%d{pref.TextFontSize}pt;" ] [ rawText requestText ]
p [ _style $"font-family:{pref.FontStack};font-size:%d{pref.TextFontSize}pt;" ] [ rawText requestText ]
|> renderHtmlNode
let plainText = (htmlToPlainText >> wordWrap 74) htmlText
// Send the e-mails

View File

@ -86,9 +86,17 @@ this.PT = {
initCKEditor() {
ClassicEditor
.create(document.querySelector("#Text"))
.then(editor => window.ckEditor = editor)
.catch(console.error)
},
/**
* Instruct the current CKEditor element to update its source (needed as htmx does not fire the submit event)
*/
updateCKEditor() {
window.ckEditor.updateElement()
},
/**
* Scripts for pages served by the Church controller
*/

View File

@ -29,11 +29,14 @@ ALTER TABLE pt."ListPreference" RENAME COLUMN "PageSize" TO page_size;
ALTER TABLE pt."ListPreference" RENAME COLUMN "AsOfDateDisplay" TO as_of_date_display;
ALTER TABLE pt."ListPreference" RENAME CONSTRAINT "PK_ListPreference" TO pk_list_preference;
ALTER TABLE pt."ListPreference" RENAME CONSTRAINT "FK_ListPreference_SmallGroup_SmallGroupId" TO fk_list_preference_small_group_id;
ALTER TABLE pt."ListPreference" RENAME CONSTRAINT "FK_ListPreference_TimeZone_TimeZoneId" TO fk_list_preference_time_zone_id;
ALTER TABLE pt."ListPreference" DROP CONSTRAINT "FK_ListPreference_TimeZone_TimeZoneId";
ALTER TABLE pt."ListPreference" RENAME TO list_preference;
ALTER INDEX pt."IX_ListPreference_TimeZoneId" RENAME TO ix_list_preference_time_zone_id;
ALTER TABLE pt.list_preference ALTER COLUMN email_from_address SET DEFAULT 'prayer@bitbadger.solutions';
ALTER TABLE pt.list_preference ALTER COLUMN fonts SET DEFAULT 'native';
-- Small Group Member
ALTER TABLE pt."Member" RENAME COLUMN "MemberId" TO id;
ALTER TABLE pt."Member" RENAME COLUMN "SmallGroupId" TO small_group_id;
@ -77,7 +80,6 @@ ALTER TABLE pt."SmallGroup" RENAME TO small_group;
ALTER INDEX pt."IX_SmallGroup_ChurchId" RENAME TO ix_small_group_church_id;
-- Time Zone (goes away)
ALTER TABLE pt.list_preference DROP CONSTRAINT fk_list_preference_time_zone_id;
DROP TABLE pt."TimeZone";
-- User