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:
parent
ab3f8dcc43
commit
ae29a6c03b
|
@ -312,6 +312,13 @@ type ListPreferences =
|
||||||
/// How the as-of date should be automatically displayed
|
/// How the as-of date should be automatically displayed
|
||||||
AsOfDateDisplay : AsOfDateDisplay
|
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
|
/// Functions to support list preferences
|
||||||
module ListPreferences =
|
module ListPreferences =
|
||||||
|
@ -323,8 +330,8 @@ module ListPreferences =
|
||||||
DaysToKeepNew = 7
|
DaysToKeepNew = 7
|
||||||
LongTermUpdateWeeks = 4
|
LongTermUpdateWeeks = 4
|
||||||
EmailFromName = "PrayerTracker"
|
EmailFromName = "PrayerTracker"
|
||||||
EmailFromAddress = "prayer@djs-consulting.com"
|
EmailFromAddress = "prayer@bitbadger.solutions"
|
||||||
Fonts = "Century Gothic,Tahoma,Luxi Sans,sans-serif"
|
Fonts = "native"
|
||||||
HeadingColor = "maroon"
|
HeadingColor = "maroon"
|
||||||
LineColor = "navy"
|
LineColor = "navy"
|
||||||
HeadingFontSize = 16
|
HeadingFontSize = 16
|
||||||
|
|
|
@ -98,6 +98,15 @@ let expirationTests =
|
||||||
[<Tests>]
|
[<Tests>]
|
||||||
let listPreferencesTests =
|
let listPreferencesTests =
|
||||||
testList "ListPreferences" [
|
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" {
|
test "empty is as expected" {
|
||||||
let mt = ListPreferences.empty
|
let mt = ListPreferences.empty
|
||||||
Expect.equal mt.SmallGroupId.Value Guid.Empty "The small group ID should have been an empty GUID"
|
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.EmailFromName "PrayerTracker" "The default e-mail from name should have been PrayerTracker"
|
||||||
Expect.equal mt.EmailFromAddress "prayer@djs-consulting.com"
|
Expect.equal mt.EmailFromAddress "prayer@djs-consulting.com"
|
||||||
"The default e-mail from address should have been 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.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 heding line color should have been navy"
|
||||||
Expect.equal mt.HeadingFontSize 16 "The default heading font size should have been 16"
|
Expect.equal mt.HeadingFontSize 16 "The default heading font size should have been 16"
|
||||||
|
|
|
@ -78,6 +78,28 @@ let namedColorList name selected attrs (s : IStringLocalizer) =
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|> select (_name name :: attrs)
|
|> 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
|
/// Generate an input[type=radio] that is selected if its value is the current value
|
||||||
let radio name domId value current =
|
let radio name domId value current =
|
||||||
input [ _type "radio"
|
input [ _type "radio"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module PrayerTracker.Views.PrayerRequest
|
module PrayerTracker.Views.PrayerRequest
|
||||||
|
|
||||||
open System
|
open System.Globalization
|
||||||
open System.IO
|
open System.IO
|
||||||
open Giraffe
|
open Giraffe
|
||||||
open Giraffe.ViewEngine
|
open Giraffe.ViewEngine
|
||||||
|
@ -17,7 +17,11 @@ let edit (model : EditRequest) today ctx viewInfo =
|
||||||
let s = I18N.localizer.Force ()
|
let s = I18N.localizer.Force ()
|
||||||
let pageTitle = if model.IsNew then "Add a New Request" else "Edit Request"
|
let pageTitle = if model.IsNew then "Add a New Request" else "Edit Request"
|
||||||
let vi = AppViewInfo.withOnLoadScript "PT.initCKEditor" viewInfo
|
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
|
csrfToken ctx
|
||||||
inputField "hidden" (nameof model.RequestId) model.RequestId []
|
inputField "hidden" (nameof model.RequestId) model.RequestId []
|
||||||
div [ _fieldRow ] [
|
div [ _fieldRow ] [
|
||||||
|
@ -79,7 +83,7 @@ let email model viewInfo =
|
||||||
let pageTitle = $"""{s["Prayer Requests"].Value} • {model.SmallGroup.Name}"""
|
let pageTitle = $"""{s["Prayer Requests"].Value} • {model.SmallGroup.Name}"""
|
||||||
let prefs = model.SmallGroup.Preferences
|
let prefs = model.SmallGroup.Preferences
|
||||||
let addresses = model.Recipients |> List.map (fun mbr -> $"{mbr.Name} <{mbr.Email}>") |> String.concat ", "
|
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"]
|
locStr s["The request list was sent to the following people, via individual e-mails"]
|
||||||
rawText ":"
|
rawText ":"
|
||||||
br []
|
br []
|
||||||
|
@ -202,7 +206,7 @@ let maintain (model : MaintainRequests) (ctx : HttpContext) viewInfo =
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
div [ updateClass ] [
|
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 [ _class "cell" ] [ locStr types[req.RequestType] ]
|
||||||
div [ expiredClass ] [ str (match req.Requestor with Some r -> r | None -> " ") ]
|
div [ expiredClass ] [ str (match req.Requestor with Some r -> r | None -> " ") ]
|
||||||
|
@ -300,7 +304,7 @@ let print model version =
|
||||||
rawText (model.AsHtml s)
|
rawText (model.AsHtml s)
|
||||||
br []
|
br []
|
||||||
hr []
|
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"""
|
img [ _src $"""/img/{s["footer_en"].Value}.png"""
|
||||||
_style "vertical-align:text-bottom;"
|
_style "vertical-align:text-bottom;"
|
||||||
_alt imgAlt
|
_alt imgAlt
|
||||||
|
@ -317,7 +321,7 @@ let view model viewInfo =
|
||||||
let s = I18N.localizer.Force ()
|
let s = I18N.localizer.Force ()
|
||||||
let pageTitle = $"""{s["Prayer Requests"].Value} • {model.SmallGroup.Name}"""
|
let pageTitle = $"""{s["Prayer Requests"].Value} • {model.SmallGroup.Name}"""
|
||||||
let spacer = rawText " "
|
let spacer = rawText " "
|
||||||
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" ] [
|
[ div [ _class "pt-center-text" ] [
|
||||||
br []
|
br []
|
||||||
a [ _class "pt-icon-link"
|
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)
|
if date.DayOfWeek = IsoDayOfWeek.Sunday then date else findSunday (date.PlusDays 1)
|
||||||
let sunday = findSunday model.Date
|
let sunday = findSunday model.Date
|
||||||
a [ _class "pt-icon-link"
|
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 ] [
|
_title s["List for Next Sunday"].Value ] [
|
||||||
icon "update"; rawText " "; locStr s["List for Next Sunday"]
|
icon "update"; rawText " "; locStr s["List for Next Sunday"]
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,7 +14,11 @@ let announcement isAdmin ctx viewInfo =
|
||||||
let model = { SendToClass = ""; Text = ""; AddToRequestList = None; RequestType = None }
|
let model = { SendToClass = ""; Text = ""; AddToRequestList = None; RequestType = None }
|
||||||
let reqTypes = ReferenceList.requestTypeList s
|
let reqTypes = ReferenceList.requestTypeList s
|
||||||
let vi = AppViewInfo.withOnLoadScript "PT.smallGroup.announcement.onPageLoad" viewInfo
|
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
|
csrfToken ctx
|
||||||
div [ _fieldRow ] [
|
div [ _fieldRow ] [
|
||||||
div [ _inputFieldWith [ "pt-editor" ] ] [
|
div [ _inputFieldWith [ "pt-editor" ] ] [
|
||||||
|
@ -461,7 +465,7 @@ let preferences (model : EditPreferences) ctx viewInfo =
|
||||||
input [ _type "color"
|
input [ _type "color"
|
||||||
_name (nameof model.LineColor)
|
_name (nameof model.LineColor)
|
||||||
_id $"{nameof model.LineColor}_Color"
|
_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 ]
|
if not (model.LineColor.StartsWith "#") then _disabled ]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
@ -483,7 +487,7 @@ let preferences (model : EditPreferences) ctx viewInfo =
|
||||||
input [ _type "color"
|
input [ _type "color"
|
||||||
_name (nameof model.HeadingColor)
|
_name (nameof model.HeadingColor)
|
||||||
_id $"{nameof model.HeadingColor}_Color"
|
_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 ]
|
if not (model.HeadingColor.StartsWith "#") then _disabled ]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
|
@ -778,7 +778,7 @@ with
|
||||||
let p = this.SmallGroup.Preferences
|
let p = this.SmallGroup.Preferences
|
||||||
let asOfSize = Math.Round (float p.TextFontSize * 0.8, 2)
|
let asOfSize = Math.Round (float p.TextFontSize * 0.8, 2)
|
||||||
[ if this.ShowHeader then
|
[ 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;" ] [
|
span [ _style $"font-size:%i{p.HeadingFontSize}pt;" ] [
|
||||||
strong [] [ str s["Prayer Requests"].Value ]
|
strong [] [ str s["Prayer Requests"].Value ]
|
||||||
]
|
]
|
||||||
|
@ -792,7 +792,7 @@ with
|
||||||
br []
|
br []
|
||||||
for _, name, reqs in this.RequestsByType s do
|
for _, name, reqs in this.RequestsByType s do
|
||||||
div [ _style "padding-left:10px;padding-bottom:.5em;" ] [
|
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 [] [
|
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;" ] [
|
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 " "; str name.Value; rawText " "
|
rawText " "; str name.Value; rawText " "
|
||||||
|
@ -804,7 +804,7 @@ with
|
||||||
reqs
|
reqs
|
||||||
|> List.map (fun req ->
|
|> List.map (fun req ->
|
||||||
let bullet = if this.IsNew req then "circle" else "disc"
|
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
|
match req.Requestor with
|
||||||
| Some r when r <> "" ->
|
| Some r when r <> "" ->
|
||||||
strong [] [ str r ]
|
strong [] [ str r ]
|
||||||
|
|
|
@ -260,7 +260,7 @@ let sendAnnouncement : HttpHandler = requireAccess [ User ] >=> validateCsrf >=>
|
||||||
// Reformat the text to use the class's font stylings
|
// Reformat the text to use the class's font stylings
|
||||||
let requestText = ckEditorToText model.Text
|
let requestText = ckEditorToText model.Text
|
||||||
let htmlText =
|
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
|
|> renderHtmlNode
|
||||||
let plainText = (htmlToPlainText >> wordWrap 74) htmlText
|
let plainText = (htmlToPlainText >> wordWrap 74) htmlText
|
||||||
// Send the e-mails
|
// Send the e-mails
|
||||||
|
|
|
@ -86,9 +86,17 @@ this.PT = {
|
||||||
initCKEditor() {
|
initCKEditor() {
|
||||||
ClassicEditor
|
ClassicEditor
|
||||||
.create(document.querySelector("#Text"))
|
.create(document.querySelector("#Text"))
|
||||||
|
.then(editor => window.ckEditor = editor)
|
||||||
.catch(console.error)
|
.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
|
* Scripts for pages served by the Church controller
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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 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 "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_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 TABLE pt."ListPreference" RENAME TO list_preference;
|
||||||
|
|
||||||
ALTER INDEX pt."IX_ListPreference_TimeZoneId" RENAME TO ix_list_preference_time_zone_id;
|
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
|
-- Small Group Member
|
||||||
ALTER TABLE pt."Member" RENAME COLUMN "MemberId" TO id;
|
ALTER TABLE pt."Member" RENAME COLUMN "MemberId" TO id;
|
||||||
ALTER TABLE pt."Member" RENAME COLUMN "SmallGroupId" TO small_group_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;
|
ALTER INDEX pt."IX_SmallGroup_ChurchId" RENAME TO ix_small_group_church_id;
|
||||||
|
|
||||||
-- Time Zone (goes away)
|
-- Time Zone (goes away)
|
||||||
ALTER TABLE pt.list_preference DROP CONSTRAINT fk_list_preference_time_zone_id;
|
|
||||||
DROP TABLE pt."TimeZone";
|
DROP TABLE pt."TimeZone";
|
||||||
|
|
||||||
-- User
|
-- User
|
||||||
|
|
Loading…
Reference in New Issue
Block a user