diff --git a/internal/web/contacts.go b/internal/web/contacts.go
index 85eb394..8eb95cd 100644
--- a/internal/web/contacts.go
+++ b/internal/web/contacts.go
@@ -239,7 +239,8 @@ func (s *Server) handleContactEdit(w http.ResponseWriter, r *http.Request) {
// contactFormInput holds the parsed, validated-ish values submitted by the
// contact form, before they're translated into vCard fields.
type contactFormInput struct {
- FullName string
+ Forename string
+ Surname string
Organization string
Note string
Birthday string
@@ -284,7 +285,8 @@ func parseContactForm(r *http.Request) (contactFormInput, error) {
get := func(key string) []string { return form[key] }
in := contactFormInput{
- FullName: strings.TrimSpace(formValue(get("full_name"), 0)),
+ Forename: strings.TrimSpace(formValue(get("forename"), 0)),
+ Surname: strings.TrimSpace(formValue(get("surname"), 0)),
Organization: strings.TrimSpace(formValue(get("organization"), 0)),
Note: strings.TrimSpace(formValue(get("note"), 0)),
Birthday: strings.TrimSpace(formValue(get("birthday"), 0)),
@@ -358,11 +360,12 @@ func (s *Server) saveContactFromForm(w http.ResponseWriter, r *http.Request, use
return
}
- if in.FullName == "" {
+ if in.Forename == "" && in.Surname == "" {
form := templates.ContactFormData{
Book: book,
ID: id,
- FullName: in.FullName,
+ Forename: in.Forename,
+ Surname: in.Surname,
Organization: in.Organization,
Note: in.Note,
Birthday: in.Birthday,
@@ -371,7 +374,7 @@ func (s *Server) saveContactFromForm(w http.ResponseWriter, r *http.Request, use
Addresses: ensureAtLeastOne(in.Addresses),
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
- _ = templates.ContactForm(username, form, "Full name is required").Render(context.Background(), w)
+ _ = templates.ContactForm(username, form, "Name is required").Render(context.Background(), w)
return
}
@@ -422,16 +425,10 @@ func buildCard(uid string, in contactFormInput, existingPhoto string) vcard.Card
if uid != "" {
card.SetValue(vcard.FieldUID, uid)
}
- card.SetValue(vcard.FieldFormattedName, in.FullName)
-
- name := &vcard.Name{}
- parts := strings.Fields(in.FullName)
- if len(parts) > 0 {
- name.GivenName = parts[0]
- }
- if len(parts) > 1 {
- name.FamilyName = strings.Join(parts[1:], " ")
+ if fn := strings.TrimSpace(in.Forename + " " + in.Surname); fn != "" {
+ card.SetValue(vcard.FieldFormattedName, fn)
}
+ name := &vcard.Name{GivenName: in.Forename, FamilyName: in.Surname}
card.SetName(name)
if in.Organization != "" {
@@ -547,10 +544,22 @@ func contactFormFromCard(book, id string, data []byte) (templates.ContactFormDat
if err != nil {
return templates.ContactFormData{}, err
}
+ var forename, surname string
+ if n := card.Name(); n != nil && (n.GivenName != "" || n.FamilyName != "") {
+ forename, surname = n.GivenName, n.FamilyName
+ } else if fn := strings.TrimSpace(card.PreferredValue(vcard.FieldFormattedName)); fn != "" {
+ parts := strings.Fields(fn)
+ if len(parts) > 1 {
+ forename, surname = parts[0], strings.Join(parts[1:], " ")
+ } else {
+ forename = parts[0]
+ }
+ }
return templates.ContactFormData{
Book: book,
ID: id,
- FullName: card.PreferredValue(vcard.FieldFormattedName),
+ Forename: forename,
+ Surname: surname,
Organization: card.PreferredValue(vcard.FieldOrganization),
Note: card.PreferredValue(vcard.FieldNote),
Birthday: card.PreferredValue(vcard.FieldBirthday),
diff --git a/internal/web/templates/contacts.templ b/internal/web/templates/contacts.templ
index 394d55d..0d9cf9f 100644
--- a/internal/web/templates/contacts.templ
+++ b/internal/web/templates/contacts.templ
@@ -42,7 +42,8 @@ type AddressValue struct {
type ContactFormData struct {
Book string
ID string // empty when creating a new contact
- FullName string
+ Forename string
+ Surname string
Organization string
Birthday string // "YYYY-MM-DD", empty if not set
Note string
@@ -158,30 +159,41 @@ templ ContactsList(username, book string, contacts []ContactSummary) {
}
}
-// typeSelect renders the TYPE dropdown shared by phone/email/address rows.
+// typeSelect renders the TYPE dropdown shared by email/address rows.
templ typeSelect(name, selected string) {
+}
+
+// phoneTypeSelect renders the phone TYPE dropdown. An unspecified number is
+// shown as "Mobile" (the vCard "cell" type), matching how mobile clients
+// label a contact's main number.
+templ phoneTypeSelect(name, selected string) {
+
}
templ phoneRow(p LabeledValue) {
-
-
+
@@ -253,44 +272,44 @@ templ ContactForm(username string, data ContactFormData, errMsg string) {
class="mt-1 block w-full rounded-md border-gray-300 border px-3 py-2 shadow-sm"/>
-
+
-
+
for _, p := range data.Phones {
@phoneRow(p)
}
-
+
for _, e := range data.Emails {
@emailRow(e)
}
-
+
for _, a := range data.Addresses {
@addressRow(a)
}
diff --git a/internal/web/templates/contacts_templ.go b/internal/web/templates/contacts_templ.go
index 7580447..1a1d77e 100644
--- a/internal/web/templates/contacts_templ.go
+++ b/internal/web/templates/contacts_templ.go
@@ -50,7 +50,8 @@ type AddressValue struct {
type ContactFormData struct {
Book string
ID string // empty when creating a new contact
- FullName string
+ Forename string
+ Surname string
Organization string
Birthday string // "YYYY-MM-DD", empty if not set
Note string
@@ -115,7 +116,7 @@ func ContactsHome(username string, books []AddressBookSummary) templ.Component {
var templ_7745c5c3_Var3 templ.SafeURL
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.URL("/web/contacts/" + b.Name))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 67, Col: 52}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 68, Col: 52}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
@@ -128,7 +129,7 @@ func ContactsHome(username string, books []AddressBookSummary) templ.Component {
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(b.Name)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 67, Col: 115}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 68, Col: 115}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
@@ -141,7 +142,7 @@ func ContactsHome(username string, books []AddressBookSummary) templ.Component {
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d contact(s)", b.Count))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 68, Col: 73}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 69, Col: 73}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
@@ -204,7 +205,7 @@ func avatar(photoDataURL, sizeClass string) templ.Component {
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.ResolveAttributeValue(photoDataURL)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 81, Col: 25}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 82, Col: 25}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var8)
if templ_7745c5c3_Err != nil {
@@ -295,7 +296,7 @@ func ContactsList(username, book string, contacts []ContactSummary) templ.Compon
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(book)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 94, Col: 45}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 95, Col: 45}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
@@ -308,7 +309,7 @@ func ContactsList(username, book string, contacts []ContactSummary) templ.Compon
var templ_7745c5c3_Var15 templ.SafeURL
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinURLErrs(templ.URL("/web/contacts/" + book + "/new"))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 97, Col: 57}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 98, Col: 57}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
if templ_7745c5c3_Err != nil {
@@ -321,7 +322,7 @@ func ContactsList(username, book string, contacts []ContactSummary) templ.Compon
var templ_7745c5c3_Var16 templ.SafeURL
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinURLErrs(templ.URL("/web/contacts/" + book + "/export"))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 101, Col: 60}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 102, Col: 60}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {
@@ -334,7 +335,7 @@ func ContactsList(username, book string, contacts []ContactSummary) templ.Compon
var templ_7745c5c3_Var17 templ.SafeURL
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinURLErrs(templ.URL("/web/contacts/" + book + "/import"))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 107, Col: 60}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 108, Col: 60}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
@@ -360,7 +361,7 @@ func ContactsList(username, book string, contacts []ContactSummary) templ.Compon
var templ_7745c5c3_Var18 templ.SafeURL
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinURLErrs(templ.URL("/web/contacts/" + book + "/" + c.ID + "/edit"))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 137, Col: 75}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 138, Col: 75}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
if templ_7745c5c3_Err != nil {
@@ -373,7 +374,7 @@ func ContactsList(username, book string, contacts []ContactSummary) templ.Compon
var templ_7745c5c3_Var19 string
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(c.FullName)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 137, Col: 130}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 138, Col: 130}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
if templ_7745c5c3_Err != nil {
@@ -386,7 +387,7 @@ func ContactsList(username, book string, contacts []ContactSummary) templ.Compon
var templ_7745c5c3_Var20 string
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(c.Organization)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 139, Col: 92}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 140, Col: 92}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
if templ_7745c5c3_Err != nil {
@@ -399,7 +400,7 @@ func ContactsList(username, book string, contacts []ContactSummary) templ.Compon
var templ_7745c5c3_Var21 string
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(c.Phone)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 140, Col: 91}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 141, Col: 91}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
if templ_7745c5c3_Err != nil {
@@ -412,7 +413,7 @@ func ContactsList(username, book string, contacts []ContactSummary) templ.Compon
var templ_7745c5c3_Var22 string
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(c.Email)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 141, Col: 85}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 142, Col: 85}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
if templ_7745c5c3_Err != nil {
@@ -425,7 +426,7 @@ func ContactsList(username, book string, contacts []ContactSummary) templ.Compon
var templ_7745c5c3_Var23 templ.SafeURL
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinURLErrs(templ.URL("/web/contacts/" + book + "/" + c.ID + "/export"))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 143, Col: 77}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 144, Col: 77}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
if templ_7745c5c3_Err != nil {
@@ -438,7 +439,7 @@ func ContactsList(username, book string, contacts []ContactSummary) templ.Compon
var templ_7745c5c3_Var24 templ.SafeURL
templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinURLErrs(templ.URL("/web/contacts/" + book + "/" + c.ID + "/delete"))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 144, Col: 96}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 145, Col: 96}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
if templ_7745c5c3_Err != nil {
@@ -469,7 +470,7 @@ func ContactsList(username, book string, contacts []ContactSummary) templ.Compon
})
}
-// typeSelect renders the TYPE dropdown shared by phone/email/address rows.
+// typeSelect renders the TYPE dropdown shared by email/address rows.
func typeSelect(name, selected string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@@ -498,7 +499,7 @@ func typeSelect(name, selected string) templ.Component {
var templ_7745c5c3_Var26 string
templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.ResolveAttributeValue(name)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 163, Col: 20}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/templates/contacts.templ`, Line: 164, Col: 20}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var26)
if templ_7745c5c3_Err != nil {
@@ -514,7 +515,7 @@ func typeSelect(name, selected string) templ.Component {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, ">Sonstige
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, ">Work")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+}
+
+// phoneTypeSelect renders the phone TYPE dropdown. An unspecified number is
+// shown as "Mobile" (the vCard "cell" type), matching how mobile clients
+// label a contact's main number.
+func phoneTypeSelect(name, selected string) templ.Component {
+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+ return templ_7745c5c3_CtxErr
+ }
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var27 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var27 == nil {
+ templ_7745c5c3_Var27 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -558,33 +634,33 @@ func phoneRow(p LabeledValue) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var27 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var27 == nil {
- templ_7745c5c3_Var27 = templ.NopComponent
+ templ_7745c5c3_Var29 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var29 == nil {
+ templ_7745c5c3_Var29 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -608,12 +684,12 @@ func emailRow(p LabeledValue) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var29 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var29 == nil {
- templ_7745c5c3_Var29 = templ.NopComponent
+ templ_7745c5c3_Var31 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var31 == nil {
+ templ_7745c5c3_Var31 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -658,12 +734,12 @@ func addressRow(a AddressValue) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Var31 := templ.GetChildren(ctx)
- if templ_7745c5c3_Var31 == nil {
- templ_7745c5c3_Var31 = templ.NopComponent
+ templ_7745c5c3_Var33 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var33 == nil {
+ templ_7745c5c3_Var33 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "