From 770edf41b0416e8b580852473b94cb6b7cabfd08 Mon Sep 17 00:00:00 2001 From: kxxt Date: Thu, 12 Jan 2023 09:53:58 +0800 Subject: [PATCH 1/5] feat: almost working contact info modal --- src/popup/contact-list.mjs | 13 ++++++- src/popup/modal.css | 51 +++++++++++++++++++++++++-- src/popup/modal.mjs | 71 ++++++++++++++++++++++++++++++++++++++ src/popup/popup.html | 36 +++++++++++++++++++ 4 files changed, 167 insertions(+), 4 deletions(-) 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..2015c21 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,54 @@ #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: gray; + border-radius: 50%; + text-align: center; +} + +.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; +} + +.details__grid > div { + font-weight: bold; + text-align: center; +} + +.details__grid > p { + font-weight: normal; + margin-block: 0.5rem; +} diff --git a/src/popup/modal.mjs b/src/popup/modal.mjs index 79f2902..3c340ab 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,77 @@ 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" +); + +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 ?? "")[0]; + contactPhotoElement.style.backgroundImage = null; + } + contactNameElement.innerText = DisplayName || PrimaryEmail; + contactEmailElement.innerText = PrimaryEmail; + let html = ""; + Nickname && (html += `
${"Nickname"}

${Nickname}

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

${tz}

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

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

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

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

`); + addresses.length > 0 && + (html += `
${"Addresses"}

${addresses}

`); + tel.length > 0 && + (html += `
${"Phone Numbers"}

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

`); + Notes && (html += `
${"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..57b096a 100644 --- a/src/popup/popup.html +++ b/src/popup/popup.html @@ -141,5 +141,41 @@