Skip to content

Instantly share code, notes, and snippets.

@tbeseda
Created November 20, 2022 22:52
Show Gist options
  • Save tbeseda/6f04a24c40883f427a20aa0ccb6b2750 to your computer and use it in GitHub Desktop.
Save tbeseda/6f04a24c40883f427a20aa0ccb6b2750 to your computer and use it in GitHub Desktop.
class HCardPresenter {
// raw properties
#data;
// class consumer interface as proxy
#interface = new Proxy(this, {
get(obj, key) {
return obj[key] || obj.mf[key];
},
});
// properties proxy for #data
props = new Proxy(this, {
get(obj, key) {
return obj.#data[key] && Array.isArray(obj.#data[key])
? obj.#data[key][0]
: null;
},
});
// microformat proxy
mf = new Proxy(this, {
get(obj, key) {
if (obj.#data[key]) {
const keyString = String(key)
let type = '';
if (pProperties.has(keyString)) {
type = 'p-';
} else if (uProperties.has(keyString)) {
type = 'u-';
} else if (dtProperties.has(keyString)) {
type = 'dt-';
}
return `<span class="${type}${keyString}">${obj.props[key]}</span>`
} else {
return null;
}
}
})
constructor(data) {
if (data.type[0] === "h-card") {
this.#data = data.properties;
return this.#interface;
} else {
throw "Invalid h-card data";
}
}
// geo can be p- and/or u-
get geo() { return `<span class="p-geo u-geo">${this.props.geo}</span>` }
get ["p-geo"]() { return `<span class="p-geo">${this.props.geo}</span>` }
get ["u-geo"]() { return `<span class="u-geo">${this.props.geo}</span>` }
// helpers
get fullHonors() {
return [
this.mf["honorific-prefix"],
this.mf["given-name"],
this.mf["additional-name"],
this.mf["family-name"],
this.mf["honorific-suffix"],
this.props.nickname ? `(aka ${this.mf["nickname"]})` : null,
].join(" ");
}
get photoHtml() {
return `<img class="u-photo" src="${this.props["photo"]}" alt="${this.props.name}" />`;
}
get logoHtml() {
return `<img class="u-logo" src="${this.props["logo"]}" alt="logo" />`;
}
get nameLinkHtml() {
return `<a class="p-name u-url" href="${this.props["url"]}">${this.props.name}</a>`;
}
get emailLinkHtml() {
return `<a class="u-email" href="mailto:${this.props["email"]}">${this.props["email"]}</a>`;
}
get telLinkHtml() {
return `<a class="p-tel" href="tel:${this.props.tel}">${this.props.tel}</a>`;
}
get addressHtml() {
return `
<address class="p-adr">
${this.mf["street-address"]}<br/>
${this.mf["locality"]},
${this.mf["region"]}
${this.mf["postal-code"]}<br />
${this.mf["country-name"]}
</address>`.trim();
}
// all h-card properties; included here for Intellisense
"additional-name";
"altitude";
"category";
"country-name";
"extended-address";
"family-name";
"gender-identity";
// "geo"; // see getters below
"given-name";
"honorific-prefix";
"honorific-suffix";
"job-title";
"latitude";
"locality";
"longitude";
"name";
"nickname";
"note";
"org";
"post-office-box";
"postal-code";
"region";
"role";
"sex";
"sort-string";
"street-address";
"tel";
"logo";
"uid";
"key";
"impp";
"email";
"photo";
"url";
"anniversary";
"bday";
}
// ? dynamically set properties on HCardPresenter
export default HCardPresenter
export const pProperties = new Set([
"additional-name",
"altitude",
"category",
"country-name",
"extended-address",
"family-name",
"gender-identity",
"geo",
"given-name",
"honorific-prefix",
"honorific-suffix",
"job-title",
"latitude",
"locality",
"longitude",
"name",
"nickname",
"note",
"org",
"post-office-box",
"postal-code",
"region",
"role",
"sex",
"sort-string",
"street-address",
"tel",
]);
export const uProperties = new Set([
"logo",
"uid",
"geo",
"key",
"impp",
"email",
"photo",
"url",
]);
export const dtProperties = new Set([
"anniversary",
"bday",
]);
export const properties = new Set([
...dtProperties,
...pProperties,
...uProperties,
]);
const sally = {
items: [
{
type: ["h-card"],
properties: {
"additional-name": ["K."],
"country-name": ["U.S.A"],
"family-name": ["Ride"],
"given-name": ["Sally"],
"honorific-prefix": ["Dr."],
"honorific-suffix": ["Ph.D."],
"postal-code": ["91316"],
"street-address": ["123 Main St."],
bday: ["1951-05-26"],
email: ["sally@example.com"],
locality: ["Los Angeles"],
name: ["Sally Ride"],
nickname: ["sallykride"],
note: ["First American woman in space."],
org: ["Sally Ride Science"],
photo: ["/_public/SallyRide.jpg"],
region: ["California"],
role: ["Physicist"],
tel: ["+1.818.555.1212"],
url: ["http://sally.example.com"],
},
},
],
},
const card = new HCardPresenter(sally);
return html`
<div class="h-card">
<h2 class="text1 mb1">${card.fullHonors}</h2>
<div class="mb-1">${card.photoHtml}</div>
<p class="mb-1 font-serif tracking1 text1 italic font-light">
${card.note}
</p>
<p class="mb-4">
${card.nameLinkHtml}
${card.emailLinkHtml}
${card.telLinkHtml}
</p>
<p class="mb-1">
${card.role},
<span class="font-medium">${card.org}</span>
</p>
<p class="mb-1 text-1">Born: ${card.bday}</p>
<div class="text-1 leading0">
${card.addressHtml}
</div>
</div>
`;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment