From 32fd17962f075994f3aed1a7c9972906615c33f8 Mon Sep 17 00:00:00 2001 From: Boxel Submission Bot Date: Wed, 25 Mar 2026 15:47:24 +0800 Subject: [PATCH] add Business Card changes [boxel-content-hash:e81d4a243943] --- .../4a413f34-985f-4494-b58d-a0ac562ddcfc.json | 69 ++ BusinessCard/jane-doe.json | 42 ++ .../3982a9ca-860b-42ae-93b4-0b1bb644e8b1.json | 40 + .../ac3982a9-ca86-4bb2-ae13-b40b1bb644e8.json | 40 + business-card.gts | 693 ++++++++++++++++++ 5 files changed, 884 insertions(+) create mode 100644 AppListing/4a413f34-985f-4494-b58d-a0ac562ddcfc.json create mode 100644 BusinessCard/jane-doe.json create mode 100644 Spec/3982a9ca-860b-42ae-93b4-0b1bb644e8b1.json create mode 100644 Spec/ac3982a9-ca86-4bb2-ae13-b40b1bb644e8.json create mode 100644 business-card.gts diff --git a/AppListing/4a413f34-985f-4494-b58d-a0ac562ddcfc.json b/AppListing/4a413f34-985f-4494-b58d-a0ac562ddcfc.json new file mode 100644 index 0000000..bf2077e --- /dev/null +++ b/AppListing/4a413f34-985f-4494-b58d-a0ac562ddcfc.json @@ -0,0 +1,69 @@ +{ + "data": { + "meta": { + "adoptsFrom": { + "name": "AppListing", + "module": "https://realms-staging.stack.cards/catalog/catalog-app/listing/listing" + } + }, + "type": "card", + "attributes": { + "name": "Business Card", + "images": [], + "summary": "This catalog listing defines a Business Card component designed to display personal and professional contact information. Its primary purpose is to present a structured, visually adaptable representation of a person's name, job title, company, department, contact details (email, phone, mobile, website), and physical address. The component supports multiple display formats, including detailed isolated views, embedded compact summaries, and responsive grid layouts that adapt to varying screen sizes. It emphasizes clear organization of identity, contact info, and branding elements such as logo and photo URLs, facilitating consistent and flexible presentation of business contact data.", + "cardInfo": { + "name": null, + "notes": null, + "summary": null, + "cardThumbnailURL": null + } + }, + "relationships": { + "tags": { + "links": { + "self": null + } + }, + "skills": { + "links": { + "self": null + } + }, + "license": { + "links": { + "self": null + } + }, + "specs.0": { + "links": { + "self": "../Spec/3982a9ca-860b-42ae-93b4-0b1bb644e8b1" + } + }, + "specs.1": { + "links": { + "self": "../Spec/ac3982a9-ca86-4bb2-ae13-b40b1bb644e8" + } + }, + "publisher": { + "links": { + "self": null + } + }, + "categories": { + "links": { + "self": null + } + }, + "examples.0": { + "links": { + "self": "../BusinessCard/jane-doe" + } + }, + "cardInfo.theme": { + "links": { + "self": null + } + } + } + } +} \ No newline at end of file diff --git a/BusinessCard/jane-doe.json b/BusinessCard/jane-doe.json new file mode 100644 index 0000000..5ae768a --- /dev/null +++ b/BusinessCard/jane-doe.json @@ -0,0 +1,42 @@ +{ + "data": { + "type": "card", + "attributes": { + "cardInfo": { + "title": "Jane Doe - VP of Engineering", + "description": "Business card for Jane Doe", + "thumbnailURL": null + }, + "fullName": "Jane Doe", + "jobTitle": "VP of Engineering", + "company": "Acme Technologies", + "department": "Engineering", + "email": "jane.doe@acmetech.com", + "phone": "+1 (555) 123-4567", + "mobile": "+1 (555) 987-6543", + "website": "https://acmetech.com", + "address": { + "street": "123 Innovation Drive", + "city": "San Francisco", + "state": "CA", + "postalCode": "94105", + "country": "United States" + }, + "logoUrl": null, + "photoUrl": null + }, + "relationships": { + "cardInfo.theme": { + "links": { + "self": null + } + } + }, + "meta": { + "adoptsFrom": { + "module": "../business-card", + "name": "BusinessCard" + } + } + } +} diff --git a/Spec/3982a9ca-860b-42ae-93b4-0b1bb644e8b1.json b/Spec/3982a9ca-860b-42ae-93b4-0b1bb644e8b1.json new file mode 100644 index 0000000..87482e9 --- /dev/null +++ b/Spec/3982a9ca-860b-42ae-93b4-0b1bb644e8b1.json @@ -0,0 +1,40 @@ +{ + "data": { + "type": "card", + "attributes": { + "readMe": null, + "ref": { + "module": "../business-card", + "name": "AddressField" + }, + "specType": "field", + "containedExamples": [], + "cardTitle": "Address", + "cardDescription": null, + "cardInfo": { + "name": null, + "summary": null, + "cardThumbnailURL": null, + "notes": null + } + }, + "relationships": { + "linkedExamples": { + "links": { + "self": null + } + }, + "cardInfo.theme": { + "links": { + "self": null + } + } + }, + "meta": { + "adoptsFrom": { + "module": "https://cardstack.com/base/spec", + "name": "Spec" + } + } + } +} \ No newline at end of file diff --git a/Spec/ac3982a9-ca86-4bb2-ae13-b40b1bb644e8.json b/Spec/ac3982a9-ca86-4bb2-ae13-b40b1bb644e8.json new file mode 100644 index 0000000..3627cce --- /dev/null +++ b/Spec/ac3982a9-ca86-4bb2-ae13-b40b1bb644e8.json @@ -0,0 +1,40 @@ +{ + "data": { + "type": "card", + "attributes": { + "readMe": null, + "ref": { + "module": "../business-card", + "name": "BusinessCard" + }, + "specType": "card", + "containedExamples": [], + "cardTitle": "Business Card", + "cardDescription": null, + "cardInfo": { + "name": null, + "summary": null, + "cardThumbnailURL": null, + "notes": null + } + }, + "relationships": { + "linkedExamples": { + "links": { + "self": null + } + }, + "cardInfo.theme": { + "links": { + "self": null + } + } + }, + "meta": { + "adoptsFrom": { + "module": "https://cardstack.com/base/spec", + "name": "Spec" + } + } + } +} \ No newline at end of file diff --git a/business-card.gts b/business-card.gts new file mode 100644 index 0000000..b0ef8d6 --- /dev/null +++ b/business-card.gts @@ -0,0 +1,693 @@ +// ═══ [EDIT TRACKING: ON] Mark all changes with ⁿ ═══ +import { CardDef, FieldDef, field, contains, Component } from 'https://cardstack.com/base/card-api'; // ¹ +import StringField from 'https://cardstack.com/base/string'; // ² +import EmailField from 'https://cardstack.com/base/email'; // ³ +import UrlField from 'https://cardstack.com/base/url'; // ⁴ +import PhoneNumberField from 'https://cardstack.com/base/phone-number'; // ⁵ +import IdCardIcon from '@cardstack/boxel-icons/id-card'; // ⁶ + +// ⁷ Address field definition +export class AddressField extends FieldDef { + static displayName = 'Address'; + + @field street = contains(StringField); + @field city = contains(StringField); + @field state = contains(StringField); + @field postalCode = contains(StringField); + @field country = contains(StringField); + + static embedded = class Embedded extends Component { + + }; + + static atom = class Atom extends Component { + + }; +} + +// ⁸ Business Card definition +export class BusinessCard extends CardDef { + static displayName = 'Business Card'; + static icon = IdCardIcon; + + // ⁹ Core identity fields + @field fullName = contains(StringField); + @field jobTitle = contains(StringField); + @field company = contains(StringField); + @field department = contains(StringField); + + // ¹⁰ Contact fields + @field email = contains(EmailField); + @field phone = contains(PhoneNumberField); + @field mobile = contains(PhoneNumberField); + @field website = contains(UrlField); + + // ¹¹ Location + @field address = contains(AddressField); + + // ¹² Branding + @field logoUrl = contains(UrlField); + @field photoUrl = contains(UrlField); + + // ¹³ Computed title + @field cardTitle = contains(StringField, { + computeVia: function(this: BusinessCard) { + return this.cardInfo?.title ?? this.fullName ?? 'Untitled Business Card'; + } + }); + + // ¹⁴ Isolated format - full detailed view + static isolated = class Isolated extends Component { + + }; + + // ¹⁵ Embedded format - compact for lists + static embedded = class Embedded extends Component { + + }; + + // ¹⁶ Fitted format - adaptive grid/gallery display + static fitted = class Fitted extends Component { + + + get initials() { + const name = this.args.model?.fullName ?? ''; + const parts = name.trim().split(/\s+/); + if (parts.length >= 2) { + return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase(); + } + return name.slice(0, 2).toUpperCase() || '??'; + } + }; +}