diff --git a/src/_locales/en-US/messages.json b/src/_locales/en-US/messages.json index 158aa5c..899eae3 100644 --- a/src/_locales/en-US/messages.json +++ b/src/_locales/en-US/messages.json @@ -118,6 +118,27 @@ "popup.input.title": { "message": "Please enter a (sub)category" }, + "popup.detail.nickname": { + "message": "Nickname" + }, + "popup.detail.timezone": { + "message": "Timezone" + }, + "popup.detail.emails": { + "message": "Emails" + }, + "popup.detail.websites": { + "message": "Websites" + }, + "popup.detail.addresses": { + "message": "Addresses" + }, + "popup.detail.phone-numbers": { + "message": "Phone Numbers" + }, + "popup.detail.notes": { + "message": "Notes" + }, "tree.category.all": { "message": "All contacts" }, diff --git a/src/_locales/es-AR/messages.json b/src/_locales/es-AR/messages.json index 2e473c5..c90401f 100644 --- a/src/_locales/es-AR/messages.json +++ b/src/_locales/es-AR/messages.json @@ -118,6 +118,27 @@ "popup.input.title": { "message": "Please enter a (sub)category" }, + "popup.detail.nickname": { + "message": "Nickname" + }, + "popup.detail.timezone": { + "message": "Timezone" + }, + "popup.detail.emails": { + "message": "Emails" + }, + "popup.detail.websites": { + "message": "Websites" + }, + "popup.detail.addresses": { + "message": "Addresses" + }, + "popup.detail.phone-numbers": { + "message": "Phone Numbers" + }, + "popup.detail.notes": { + "message": "Notes" + }, "tree.category.all": { "message": "Todos los contactos" }, diff --git a/src/_locales/es-ES/messages.json b/src/_locales/es-ES/messages.json index ed4fd62..ddafeca 100644 --- a/src/_locales/es-ES/messages.json +++ b/src/_locales/es-ES/messages.json @@ -118,6 +118,27 @@ "popup.input.title": { "message": "Please enter a (sub)category" }, + "popup.detail.nickname": { + "message": "Nickname" + }, + "popup.detail.timezone": { + "message": "Timezone" + }, + "popup.detail.emails": { + "message": "Emails" + }, + "popup.detail.websites": { + "message": "Websites" + }, + "popup.detail.addresses": { + "message": "Addresses" + }, + "popup.detail.phone-numbers": { + "message": "Phone Numbers" + }, + "popup.detail.notes": { + "message": "Notes" + }, "tree.category.all": { "message": "Todos los contactos" }, diff --git a/src/_locales/fr/messages.json b/src/_locales/fr/messages.json index cd9d2c1..012c307 100644 --- a/src/_locales/fr/messages.json +++ b/src/_locales/fr/messages.json @@ -118,6 +118,27 @@ "popup.input.title": { "message": "Please enter a (sub)category" }, + "popup.detail.nickname": { + "message": "Nickname" + }, + "popup.detail.timezone": { + "message": "Timezone" + }, + "popup.detail.emails": { + "message": "Emails" + }, + "popup.detail.websites": { + "message": "Websites" + }, + "popup.detail.addresses": { + "message": "Addresses" + }, + "popup.detail.phone-numbers": { + "message": "Phone Numbers" + }, + "popup.detail.notes": { + "message": "Notes" + }, "tree.category.all": { "message": "Tous les contacts" }, diff --git a/src/_locales/nl/messages.json b/src/_locales/nl/messages.json index 3bd9aed..8d6856a 100644 --- a/src/_locales/nl/messages.json +++ b/src/_locales/nl/messages.json @@ -118,6 +118,27 @@ "popup.input.title": { "message": "Please enter a (sub)category" }, + "popup.detail.nickname": { + "message": "Nickname" + }, + "popup.detail.timezone": { + "message": "Timezone" + }, + "popup.detail.emails": { + "message": "Emails" + }, + "popup.detail.websites": { + "message": "Websites" + }, + "popup.detail.addresses": { + "message": "Addresses" + }, + "popup.detail.phone-numbers": { + "message": "Phone Numbers" + }, + "popup.detail.notes": { + "message": "Notes" + }, "tree.category.all": { "message": "Alle contacten" }, diff --git a/src/_locales/pt-BR/messages.json b/src/_locales/pt-BR/messages.json index 1993c59..34da2f0 100644 --- a/src/_locales/pt-BR/messages.json +++ b/src/_locales/pt-BR/messages.json @@ -118,6 +118,27 @@ "popup.input.title": { "message": "Please enter a (sub)category" }, + "popup.detail.nickname": { + "message": "Nickname" + }, + "popup.detail.timezone": { + "message": "Timezone" + }, + "popup.detail.emails": { + "message": "Emails" + }, + "popup.detail.websites": { + "message": "Websites" + }, + "popup.detail.addresses": { + "message": "Addresses" + }, + "popup.detail.phone-numbers": { + "message": "Phone Numbers" + }, + "popup.detail.notes": { + "message": "Notes" + }, "tree.category.all": { "message": "Todos os contatos" }, diff --git a/src/_locales/ru/messages.json b/src/_locales/ru/messages.json index cff6633..91d3003 100644 --- a/src/_locales/ru/messages.json +++ b/src/_locales/ru/messages.json @@ -118,6 +118,27 @@ "popup.input.title": { "message": "Please enter a (sub)category" }, + "popup.detail.nickname": { + "message": "Nickname" + }, + "popup.detail.timezone": { + "message": "Timezone" + }, + "popup.detail.emails": { + "message": "Emails" + }, + "popup.detail.websites": { + "message": "Websites" + }, + "popup.detail.addresses": { + "message": "Addresses" + }, + "popup.detail.phone-numbers": { + "message": "Phone Numbers" + }, + "popup.detail.notes": { + "message": "Notes" + }, "tree.category.all": { "message": "Все контакты" }, diff --git a/src/_locales/zh-CN/messages.json b/src/_locales/zh-CN/messages.json index bcfd318..a774da8 100644 --- a/src/_locales/zh-CN/messages.json +++ b/src/_locales/zh-CN/messages.json @@ -27,16 +27,16 @@ "message": "正在更新..." }, "manifest_action_title": { - "message": "Categories" + "message": "类别管理器" }, "manifest_description": { "message": "联系人类别管理器。你可以一次向整个类别的联系人发送邮件(基于类别的联系人群组)。" }, "menu.category.add_members_to_current_message": { - "message": "Add category members to ..." + "message": "添加类别成员到 ..." }, "menu.category.add_members_to_new_message": { - "message": "Compose new message with category members in ..." + "message": "编辑新消息并将此类别成员添加到 ..." }, "menu.category.add_to_bcc": { "message": "Bcc" @@ -51,7 +51,7 @@ "message": "删除此类别" }, "menu.category.rename": { - "message": "Rename or move this category" + "message": "重命名或移动此类别" }, "menu.contact.context.add_to_category": { "message": "添加到 '$CATEGORY$'", @@ -118,6 +118,27 @@ "popup.input.title": { "message": "请输入(子)类别" }, + "popup.detail.nickname": { + "message": "昵称" + }, + "popup.detail.timezone": { + "message": "时区" + }, + "popup.detail.emails": { + "message": "电子邮箱" + }, + "popup.detail.websites": { + "message": "网站" + }, + "popup.detail.addresses": { + "message": "地址" + }, + "popup.detail.phone-numbers": { + "message": "电话号码" + }, + "popup.detail.notes": { + "message": "备注" + }, "tree.category.none": { "message": "未分类" }, diff --git a/src/popup/contact-list.mjs b/src/popup/contact-list.mjs index 3c0b74a..6164be1 100644 --- a/src/popup/contact-list.mjs +++ b/src/popup/contact-list.mjs @@ -3,6 +3,7 @@ import { escapeHtmlContent, escapeHtmlAttr, } from "../modules/ui/ui.mjs"; +import { showDetailModal } from "./modal.mjs"; export function createContactList(data) { let component = new Component({ @@ -34,7 +35,7 @@ export function createContactList(data) {

` ); - }) + }); } return ``; }, @@ -50,5 +51,15 @@ export function createContactList(data) { e.target.dataset.addressbook + "\n" + e.target.dataset.id ); }); + component.element.addEventListener("click", (e) => { + let target = e.target; + if (target.dataset.id == null) + // Possibly click on children elements + target = target.parentElement; + if (target.dataset.id == null) + // Not a click on a contact + return; + showDetailModal(target.dataset.id); + }); return component; } diff --git a/src/popup/modal.css b/src/popup/modal.css index 94e5289..d6d4a94 100644 --- a/src/popup/modal.css +++ b/src/popup/modal.css @@ -49,6 +49,8 @@ line-height: 1.25; color: #00449e; box-sizing: border-box; + display: inline-flex; + align-items: center; } .modal__close { @@ -183,11 +185,69 @@ #modal-error-title { color: red; - display: inline-flex; - align-items: center; font-size: 2rem; } -#modal-error-title i { +.modal__title > i { margin-right: 1rem; } + +.details__header-container { + display: flex; + align-items: center; +} + +.details__photo { + width: 3rem; + height: 3rem; + line-height: 3rem; + background-size: contain !important; + background-color: lightgray; + border-radius: 50%; + text-align: center; + color: orangered; + font-weight: bold; +} + +.details__header { + margin-left: 1.2rem; +} + +.details__name { + font-size: 1.3rem; + font-weight: bold; +} + +.details__email { + font-size: 1rem; +} + +.details__grid { + display: grid; + grid-template-columns: auto auto; + column-gap: 1rem; + align-items: center; + overflow: scroll; + max-height: 24rem; +} + +.details__grid > div:nth-child(2n + 1) { + font-weight: bold; + text-align: center; +} + +.details__grid > p { + font-weight: normal; + margin-block: 0.5rem; + word-break: break-all; + hyphens: auto; +} + +#modal-details .modal__container { + max-height: 80vh; + max-width: 80vw; +} + +#modal-details-content { + margin-bottom: 0; +} diff --git a/src/popup/modal.mjs b/src/popup/modal.mjs index 79f2902..90c70e6 100644 --- a/src/popup/modal.mjs +++ b/src/popup/modal.mjs @@ -7,6 +7,7 @@ import { validateCategoryString, } from "../modules/cache/index.mjs"; import { printToConsole } from "../modules/utils.mjs"; +import { escapeHtmlContent, escapeHtmlAttr } from "../modules/ui/ui.mjs"; const categoryInput = document.getElementById("category-input"); const categoryInputError = document.getElementById("category-input-error"); @@ -99,7 +100,95 @@ document.getElementById("modal-error-content-footer").innerText = await browser.i18n.getMessage("popup.error.content.footer"); document.querySelector("#modal-error .modal__footer button").innerText = await browser.i18n.getMessage("popup.input.button.ok"); + export function showErrorModal(errorMessage) { errorContent.innerText = errorMessage; MicroModal.show("modal-error"); } + +const contactNameElement = document.querySelector( + "#modal-details .details__name" +); +const contactPhotoElement = document.querySelector( + "#modal-details .details__photo" +); +const contactEmailElement = document.querySelector( + "#modal-details .details__email" +); + +const LABEL_NICKNAME = await browser.i18n.getMessage("popup.detail.nickname"); +const LABEL_TIMEZONE = await browser.i18n.getMessage("popup.detail.timezone"); +const LABEL_EMAILS = await browser.i18n.getMessage("popup.detail.emails"); +const LABEL_WEBSITES = await browser.i18n.getMessage("popup.detail.websites"); +const LABEL_ADDRESSES = await browser.i18n.getMessage("popup.detail.addresses"); +const LABEL_PHONE_NUMBERS = await browser.i18n.getMessage( + "popup.detail.phone-numbers" +); +const LABEL_NOTES = await browser.i18n.getMessage("popup.detail.notes"); + +export async function showDetailModal(contactId) { + const { + properties: { vCard, PrimaryEmail, DisplayName = "", Nickname, Notes }, + } = await browser.contacts.get(contactId); + const component = new ICAL.Component(ICAL.parse(vCard)); + const allEmails = component + .getAllProperties("email") + .flatMap((x) => x.getValues()); + const photo = component.getFirstPropertyValue("photo"); + const tz = component.getFirstPropertyValue("tz"); + const urls = component.getAllProperties("url").flatMap((x) => x.getValues()); + const addresses = component + .getAllProperties("adr") + .flatMap((x) => x.getValues()); + const tel = component.getAllProperties("tel").flatMap((x) => x.getValues()); + if (photo) { + contactPhotoElement.style.backgroundImage = `url(${photo})`; + contactPhotoElement.innerText = null; + } else { + contactPhotoElement.innerText = DisplayName.trim()[0] ?? ""; + contactPhotoElement.style.backgroundImage = null; + } + contactNameElement.innerText = DisplayName ?? ""; + contactEmailElement.innerText = PrimaryEmail ?? ""; + let html = ""; + Nickname && (html += `
${LABEL_NICKNAME}

${Nickname}

`); + tz && (html += `
${LABEL_TIMEZONE}

${tz}

`); + allEmails.length > 0 && + (html += `
${LABEL_EMAILS}

${allEmails.reduce((acc, cur) => { + return ( + acc + + `${escapeHtmlContent( + cur + )}
` + ); + }, "")}

`); + urls.length > 0 && + (html += `
${LABEL_WEBSITES}

${urls.reduce( + (acc, cur) => + acc + + `${escapeHtmlContent(cur)}
`, + "" + )}

`); + addresses.length > 0 && + (html += `
${LABEL_ADDRESSES}
${addresses + .map((address) => + address.reduce( + (acc, cur) => (cur ? acc + `${escapeHtmlContent(cur)}
` : acc), + "" + ) + ) + .join("
")}
`); + tel.length > 0 && + (html += `
${LABEL_PHONE_NUMBERS}

${tel.reduce( + (acc, cur) => + acc + + `${escapeHtmlContent( + cur + )}
`, + "" + )}

`); + Notes && + (html += `
${LABEL_NOTES}

${escapeHtmlContent(Notes)}

`); + document.querySelector("#modal-details .details__grid").innerHTML = html; + MicroModal.show("modal-details"); +} diff --git a/src/popup/popup.html b/src/popup/popup.html index 0052f45..fcc7607 100644 --- a/src/popup/popup.html +++ b/src/popup/popup.html @@ -141,5 +141,35 @@