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 @@
+