From bd790cce1f4d6474db856133112767ec325d6b78 Mon Sep 17 00:00:00 2001 From: Jasper Moelker Date: Sat, 28 Dec 2024 13:18:08 +0100 Subject: [PATCH 1/4] feat(ActionBlock): add ExternalLink --- config/datocms/lib/fields.ts | 23 +++++ .../migrations/1734363388_actionBlock.ts | 21 +---- .../migrations/1735337726_externalLinks.ts | 93 +++++++++++++++++++ datocms-environment.ts | 2 +- src/blocks/ActionBlock/ActionBlock.astro | 30 ++++-- .../ActionBlock/ActionBlock.fragment.graphql | 4 + src/blocks/ActionBlock/ActionBlock.test.ts | 35 ++++++- .../ActionBlock/ExternalLink.fragment.graphql | 8 ++ 8 files changed, 185 insertions(+), 31 deletions(-) create mode 100644 config/datocms/lib/fields.ts create mode 100644 config/datocms/migrations/1735337726_externalLinks.ts create mode 100644 src/blocks/ActionBlock/ExternalLink.fragment.graphql diff --git a/config/datocms/lib/fields.ts b/config/datocms/lib/fields.ts new file mode 100644 index 0000000..c30a4ee --- /dev/null +++ b/config/datocms/lib/fields.ts @@ -0,0 +1,23 @@ +import type { SimpleSchemaTypes } from '@datocms/cli/lib/cma-client-node'; + +export const actionStyleField: SimpleSchemaTypes.FieldCreateSchema = { + label: 'Style', + field_type: 'string', + api_key: 'style', + validators: { + required: {}, + enum: { values: ['default', 'primary', 'secondary'] }, + }, + appearance: { + addons: [], + editor: 'string_select', + parameters: { + options: [ + { hint: '', label: 'Default action', value: 'default' }, + { hint: '', label: 'Primary action', value: 'primary' }, + { hint: '', label: 'Secondary action', value: 'secondary' }, + ], + }, + }, + default_value: 'default', +}; diff --git a/config/datocms/migrations/1734363388_actionBlock.ts b/config/datocms/migrations/1734363388_actionBlock.ts index cf68e68..12794bc 100644 --- a/config/datocms/migrations/1734363388_actionBlock.ts +++ b/config/datocms/migrations/1734363388_actionBlock.ts @@ -1,4 +1,5 @@ import { Client } from '@datocms/cli/lib/cma-client-node'; +import { actionStyleField } from '../lib/fields'; export default async function (client: Client) { console.log('Create new models/block models'); @@ -102,25 +103,7 @@ export default async function (client: Client) { ); await client.fields.create('GWnhoQDqQoGJj4-sQTVttw', { id: 'S3JQgijhRmalePX3GeugPg', - label: 'Style', - field_type: 'string', - api_key: 'style', - validators: { - required: {}, - enum: { values: ['default', 'primary', 'secondary'] }, - }, - appearance: { - addons: [], - editor: 'string_select', - parameters: { - options: [ - { hint: '', label: 'Default action', value: 'default' }, - { hint: '', label: 'Primary action', value: 'primary' }, - { hint: '', label: 'Secondary action', value: 'secondary' }, - ], - }, - }, - default_value: 'default', + ...actionStyleField, }); console.log('Update existing fields/fieldsets'); diff --git a/config/datocms/migrations/1735337726_externalLinks.ts b/config/datocms/migrations/1735337726_externalLinks.ts new file mode 100644 index 0000000..c935d06 --- /dev/null +++ b/config/datocms/migrations/1735337726_externalLinks.ts @@ -0,0 +1,93 @@ +import type { Client } from '@datocms/cli/lib/cma-client-node'; +import { actionStyleField } from '../lib/fields'; + +export default async function (client: Client) { + console.log('Create new models/block models'); + + console.log( + 'Create block model "\uD83D\uDD17 External Link" (`external_link`)' + ); + await client.itemTypes.create( + { + id: 'Yk1ge9eTTf25Iwph1Dx3_g', + name: '\uD83D\uDD17 External Link', + api_key: 'external_link', + modular_block: true, + inverse_relationships_enabled: false, + }, + { + skip_menu_item_creation: true, + schema_menu_item_id: 'OiBwyNPrR82ZWMawg47csg', + } + ); + + console.log('Creating new fields/fieldsets'); + + console.log( + 'Create Single-line string field "Title" (`title`) in block model "\uD83D\uDD17 External Link" (`external_link`)' + ); + await client.fields.create('Yk1ge9eTTf25Iwph1Dx3_g', { + id: 'Epmmtd7MTfeqpiwLP23D1Q', + label: 'Title', + field_type: 'string', + api_key: 'title', + validators: { required: {} }, + appearance: { + addons: [], + editor: 'single_line', + parameters: { heading: false, placeholder: null }, + }, + default_value: '', + }); + + console.log( + 'Create Single-line string field "URL" (`url`) in block model "\uD83D\uDD17 External Link" (`external_link`)' + ); + await client.fields.create('Yk1ge9eTTf25Iwph1Dx3_g', { + id: 'bUvYLCENQ3SP_vGhoN07nA', + label: 'URL', + field_type: 'string', + api_key: 'url', + validators: { required: {}, format: { predefined_pattern: 'url' } }, + appearance: { + addons: [], + editor: 'single_line', + parameters: { heading: false, placeholder: null }, + }, + default_value: '', + }); + + console.log( + 'Create Boolean field "Open in new tab" (`open_in_new_tab`) in block model "\uD83D\uDD17 External Link" (`external_link`)' + ); + await client.fields.create('Yk1ge9eTTf25Iwph1Dx3_g', { + id: 'AlPRQFQdRlixBp4Tgz5qsQ', + label: 'Open in new tab', + field_type: 'boolean', + api_key: 'open_in_new_tab', + appearance: { addons: [], editor: 'boolean', parameters: {} }, + default_value: false, + }); + + console.log( + 'Create Single-line string field "Style" (`style`) in block model "\uD83D\uDD17 External Link" (`external_link`)' + ); + await client.fields.create('Yk1ge9eTTf25Iwph1Dx3_g', { + id: 'TNl63OntSe6ZLD3wCYxK-g', + ...actionStyleField, + }); + + console.log('Update existing fields/fieldsets'); + + console.log( + 'Update Modular Content (Multiple blocks) field "Items" (`items`) in block model "\uD83C\uDF9B\uFE0F Action Block" (`action_block`)' + ); + await client.fields.update('dAUckF8qR0edf_f7zam6hA', { + validators: { + rich_text_blocks: { + item_types: ['GWnhoQDqQoGJj4-sQTVttw', 'Yk1ge9eTTf25Iwph1Dx3_g'], + }, + size: { min: 1 }, + }, + }); +} diff --git a/datocms-environment.ts b/datocms-environment.ts index c66777e..315ea0e 100644 --- a/datocms-environment.ts +++ b/datocms-environment.ts @@ -3,5 +3,5 @@ * @see docs/getting-started.md on how to use this file * @see docs/decision-log/2023-10-24-datocms-env-file.md on why file is preferred over env vars */ -export const datocmsEnvironment = 'action-block'; +export const datocmsEnvironment = 'external-links'; export const datocmsBuildTriggerId = '30535'; diff --git a/src/blocks/ActionBlock/ActionBlock.astro b/src/blocks/ActionBlock/ActionBlock.astro index 94b0475..1112f6e 100644 --- a/src/blocks/ActionBlock/ActionBlock.astro +++ b/src/blocks/ActionBlock/ActionBlock.astro @@ -1,5 +1,6 @@ --- import type { ActionBlockFragment } from '@lib/datocms/types'; +import Link from '@components/Link/Link.astro'; import LinkToRecord from '@components/LinkToRecord/LinkToRecord.astro'; export interface Props { @@ -7,18 +8,31 @@ export interface Props { } const { block } = Astro.props; const { items } = block; +const actionClassList = (style: string) => ['action', `action--${style}`]; ---
{ - items.map((item) => ( - - {item.title} - - )) + items.map((item) => + item.__typename === 'InternalLinkRecord' ? ( + + {item.title} + + ) : item.__typename === 'ExternalLinkRecord' ? ( + + {item.title} + + ) : ( + + ) + ) }
diff --git a/src/blocks/ActionBlock/ActionBlock.fragment.graphql b/src/blocks/ActionBlock/ActionBlock.fragment.graphql index e8a9c91..a2c0931 100644 --- a/src/blocks/ActionBlock/ActionBlock.fragment.graphql +++ b/src/blocks/ActionBlock/ActionBlock.fragment.graphql @@ -1,4 +1,5 @@ #import './InternalLink.fragment.graphql' +#import './ExternalLink.fragment.graphql' fragment ActionBlock on ActionBlockRecord { __typename @@ -8,5 +9,8 @@ fragment ActionBlock on ActionBlockRecord { ... on InternalLinkRecord { ...InternalLink } + ... on ExternalLinkRecord { + ...ExternalLink + } } } diff --git a/src/blocks/ActionBlock/ActionBlock.test.ts b/src/blocks/ActionBlock/ActionBlock.test.ts index f5a9acb..6b1f370 100644 --- a/src/blocks/ActionBlock/ActionBlock.test.ts +++ b/src/blocks/ActionBlock/ActionBlock.test.ts @@ -1,9 +1,13 @@ import { renderToFragment } from '@lib/renderer'; import { describe, expect, test } from 'vitest'; import InlineBlock, { type Props } from './ActionBlock.astro'; -import type { ActionBlockFragment, InternalLinkFragment, SiteLocale } from '@lib/datocms/types'; +import type { ActionBlockFragment, ExternalLinkFragment, InternalLinkFragment, SiteLocale } from '@lib/datocms/types'; import { locales } from '@lib/i18n'; +type ActionBlockItem = + | InternalLinkFragment + | ExternalLinkFragment; + const createInternalLinkFragment = (title: string, slug: string, style: string) => ({ '__typename': 'InternalLinkRecord', 'id': `${slug}-123`, @@ -19,14 +23,23 @@ const createInternalLinkFragment = (title: string, slug: string, style: string) } } satisfies InternalLinkFragment); -const createActionBlockFragment = (items: InternalLinkFragment[]) => ({ +const createExternalLinkFragment = (title: string, url: string, style: string) => ({ + '__typename': 'ExternalLinkRecord', + 'id': `${url}-123`, + 'title': title, + 'style': style, + 'openInNewTab': false, + 'url': url +} satisfies ExternalLinkFragment); + +const createActionBlockFragment = (items: ActionBlockItem[]) => ({ '__typename': 'ActionBlockRecord', 'id': 'PL9XQGyWQjuyHpdDNsXCNg', 'items': items } satisfies ActionBlockFragment); describe('ActionBlock', () => { - test('Block is rendered', async () => { + test('Block is rendered with internal links', async () => { const blockWithTwoItems = createActionBlockFragment([ createInternalLinkFragment('First item', 'first-item', 'primary'), createInternalLinkFragment('Second item', 'second-item', 'secondary'), @@ -42,4 +55,20 @@ describe('ActionBlock', () => { expect(fragment.querySelector('a.action--secondary')?.textContent).toBe('Second item'); }); + test('Block is rendered with external links', async () => { + const blockWithTwoItems = createActionBlockFragment([ + createExternalLinkFragment('First item', 'https://example.com/first', 'primary'), + createExternalLinkFragment('Second item', 'https://example.com/second', 'secondary'), + ]); + const fragment = await renderToFragment(InlineBlock, { + props: { + block: blockWithTwoItems, + } + }); + + expect(fragment.querySelectorAll('a.action').length).toBe(2); + expect(fragment.querySelector('a.action--primary')?.textContent).toBe('First item'); + expect(fragment.querySelector('a.action--secondary')?.textContent).toBe('Second item'); + }); + }); diff --git a/src/blocks/ActionBlock/ExternalLink.fragment.graphql b/src/blocks/ActionBlock/ExternalLink.fragment.graphql new file mode 100644 index 0000000..fe308c0 --- /dev/null +++ b/src/blocks/ActionBlock/ExternalLink.fragment.graphql @@ -0,0 +1,8 @@ +fragment ExternalLink on ExternalLinkRecord { + __typename + id + title + url + openInNewTab + style +} From e3fcb93f13be923696a2265f4c1ea66c21038633 Mon Sep 17 00:00:00 2001 From: Jasper Moelker Date: Sat, 28 Dec 2024 15:21:50 +0100 Subject: [PATCH 2/4] feat(ActionBlock): PhoneLink (tel, sms, email) --- datocms-environment.ts | 2 +- package-lock.json | 10 +++++ package.json | 1 + src/blocks/ActionBlock/ActionBlock.astro | 10 +++++ .../ActionBlock/ActionBlock.fragment.graphql | 4 ++ src/blocks/ActionBlock/PhoneLink.astro | 41 +++++++++++++++++++ .../ActionBlock/PhoneLink.fragment.graphql | 9 ++++ 7 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/blocks/ActionBlock/PhoneLink.astro create mode 100644 src/blocks/ActionBlock/PhoneLink.fragment.graphql diff --git a/datocms-environment.ts b/datocms-environment.ts index 315ea0e..5861f28 100644 --- a/datocms-environment.ts +++ b/datocms-environment.ts @@ -3,5 +3,5 @@ * @see docs/getting-started.md on how to use this file * @see docs/decision-log/2023-10-24-datocms-env-file.md on why file is preferred over env vars */ -export const datocmsEnvironment = 'external-links'; +export const datocmsEnvironment = 'email-and-phone-links'; export const datocmsBuildTriggerId = '30535'; diff --git a/package-lock.json b/package-lock.json index 47cbb2b..b49672b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "jiti": "^1.20.0", "nanostores": "^0.9.5", "oembed-providers": "^1.0.20230906", + "phone": "^3.1.56", "pretty-bytes": "^6.1.1", "promise-all-props": "^3.0.0", "regexparam": "^3.0.0", @@ -15535,6 +15536,15 @@ "node": "*" } }, + "node_modules/phone": { + "version": "3.1.56", + "resolved": "https://registry.npmjs.org/phone/-/phone-3.1.56.tgz", + "integrity": "sha512-KF2asNQQqLnsutv/DQLRhiOCLkmu+0kspCc1L+EgPT688JEhkyw6hbr9U4ROvMSI6/xBw5TtdCeLSWJkaUWjyw==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/picocolors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", diff --git a/package.json b/package.json index 81690b4..91bdbfe 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "jiti": "^1.20.0", "nanostores": "^0.9.5", "oembed-providers": "^1.0.20230906", + "phone": "^3.1.56", "pretty-bytes": "^6.1.1", "promise-all-props": "^3.0.0", "regexparam": "^3.0.0", diff --git a/src/blocks/ActionBlock/ActionBlock.astro b/src/blocks/ActionBlock/ActionBlock.astro index 1112f6e..ecd9afd 100644 --- a/src/blocks/ActionBlock/ActionBlock.astro +++ b/src/blocks/ActionBlock/ActionBlock.astro @@ -2,6 +2,7 @@ import type { ActionBlockFragment } from '@lib/datocms/types'; import Link from '@components/Link/Link.astro'; import LinkToRecord from '@components/LinkToRecord/LinkToRecord.astro'; +import PhoneLink from './PhoneLink.astro'; export interface Props { block: ActionBlockFragment; @@ -29,6 +30,15 @@ const actionClassList = (style: string) => ['action', `action--${style}`]; > {item.title} + ) : item.__typename === 'PhoneLinkRecord' ? ( + + {item.title} + ) : ( ) diff --git a/src/blocks/ActionBlock/ActionBlock.fragment.graphql b/src/blocks/ActionBlock/ActionBlock.fragment.graphql index a2c0931..9b9c4b3 100644 --- a/src/blocks/ActionBlock/ActionBlock.fragment.graphql +++ b/src/blocks/ActionBlock/ActionBlock.fragment.graphql @@ -1,5 +1,6 @@ #import './InternalLink.fragment.graphql' #import './ExternalLink.fragment.graphql' +#import './PhoneLink.fragment.graphql' fragment ActionBlock on ActionBlockRecord { __typename @@ -12,5 +13,8 @@ fragment ActionBlock on ActionBlockRecord { ... on ExternalLinkRecord { ...ExternalLink } + ... on PhoneLinkRecord { + ...PhoneLink + } } } diff --git a/src/blocks/ActionBlock/PhoneLink.astro b/src/blocks/ActionBlock/PhoneLink.astro new file mode 100644 index 0000000..3b7bc3a --- /dev/null +++ b/src/blocks/ActionBlock/PhoneLink.astro @@ -0,0 +1,41 @@ +--- +import type { HTMLAttributes } from 'astro/types'; +import type { PhoneLinkFragment } from '@lib/datocms/types'; +import { phone } from 'phone'; + +type PhoneLinkProps = Pick< + PhoneLinkFragment, + 'action' | 'phoneNumber' | 'text' +>; +export type Props = HTMLAttributes<'a'> & PhoneLinkProps; +const { action, phoneNumber, text, ...props } = Astro.props; + +const formatPhoneNumber = (phoneNumber: string) => { + const output = phone(phoneNumber); + // console.log(output); + return output.isValid ? output.phoneNumber : phoneNumber.replace(/\s/g, ''); +}; + +const getHref = ({ action, phoneNumber, text }: PhoneLinkProps) => { + if (action === 'call') { + return `tel:${formatPhoneNumber(phoneNumber)}`; + } + if (action === 'sms') { + const smsNumber = formatPhoneNumber(phoneNumber); + return text + ? `sms:${smsNumber}?body=${encodeURIComponent(text)}` + : `sms:${smsNumber}`; + } + if (action === 'whatsapp') { + const whatsAppNumber = formatPhoneNumber(phoneNumber).replace('+', ''); + return text + ? `https://wa.me/${whatsAppNumber}?text=${encodeURIComponent(text)}` + : `https://wa.me/${whatsAppNumber}`; + } + return ''; +}; + +const href = getHref({ action, phoneNumber, text }); +--- + + diff --git a/src/blocks/ActionBlock/PhoneLink.fragment.graphql b/src/blocks/ActionBlock/PhoneLink.fragment.graphql new file mode 100644 index 0000000..16983e6 --- /dev/null +++ b/src/blocks/ActionBlock/PhoneLink.fragment.graphql @@ -0,0 +1,9 @@ +fragment PhoneLink on PhoneLinkRecord { + __typename + id + title + phoneNumber + action + text + style +} From 8a907e71a0fde945554fdaf0e865e357ed139160 Mon Sep 17 00:00:00 2001 From: Jasper Moelker Date: Sat, 28 Dec 2024 16:04:26 +0100 Subject: [PATCH 3/4] feat(ActionBlock): Email Link (optional subject & body) --- .../1735398092_emailAndPhoneLinks.ts | 235 ++++++++++++++++++ src/blocks/ActionBlock/ActionBlock.astro | 10 + .../ActionBlock/ActionBlock.fragment.graphql | 4 + src/blocks/ActionBlock/EmailLink.astro | 22 ++ .../ActionBlock/EmailLink.fragment.graphql | 9 + 5 files changed, 280 insertions(+) create mode 100644 config/datocms/migrations/1735398092_emailAndPhoneLinks.ts create mode 100644 src/blocks/ActionBlock/EmailLink.astro create mode 100644 src/blocks/ActionBlock/EmailLink.fragment.graphql diff --git a/config/datocms/migrations/1735398092_emailAndPhoneLinks.ts b/config/datocms/migrations/1735398092_emailAndPhoneLinks.ts new file mode 100644 index 0000000..fab34fd --- /dev/null +++ b/config/datocms/migrations/1735398092_emailAndPhoneLinks.ts @@ -0,0 +1,235 @@ +import type { Client } from '@datocms/cli/lib/cma-client-node'; +import { actionStyleField } from '../lib/fields'; + +export default async function (client: Client) { + console.log('Manage upload filters'); + + console.log('Install plugin "Dropdown Conditional Fields"'); + await client.plugins.create({ + id: 'Srdwo4YOREmRtvMAV2otlQ', + package_name: 'datocms-plugin-dropdown-conditional-fields', + }); + await client.plugins.update('Srdwo4YOREmRtvMAV2otlQ', { + parameters: { developmentMode: false }, + }); + + console.log('Create new models/block models'); + + console.log('Create block model "\uD83D\uDCDE Phone Link" (`phone_link`)'); + await client.itemTypes.create( + { + id: 'C5fWG5CYRJ69oqaP6CjYdA', + name: '\uD83D\uDCDE Phone Link', + api_key: 'phone_link', + modular_block: true, + inverse_relationships_enabled: false, + }, + { + skip_menu_item_creation: true, + schema_menu_item_id: 'YNbDA4R-Srqf0u4-Rya3Ug', + } + ); + + console.log('Create block model "\uD83D\uDCE7 Email Link" (`email_link`)'); + await client.itemTypes.create( + { + id: 'b90_c2zeS6auRELEzZHNcA', + name: '\uD83D\uDCE7 Email Link', + api_key: 'email_link', + modular_block: true, + inverse_relationships_enabled: false, + }, + { + skip_menu_item_creation: true, + schema_menu_item_id: 'Vgf9ZeHvTqeh-tMAks2jFw', + } + ); + + console.log('Creating new fields/fieldsets'); + + console.log( + 'Create Single-line string field "Title" (`title`) in block model "\uD83D\uDCDE Phone Link" (`phone_link`)' + ); + await client.fields.create('C5fWG5CYRJ69oqaP6CjYdA', { + id: 'fp9Cugu8QlKqawis3QTnPA', + label: 'Title', + field_type: 'string', + api_key: 'title', + validators: { required: {} }, + appearance: { + addons: [], + editor: 'single_line', + parameters: { heading: false, placeholder: null }, + }, + default_value: '', + }); + + console.log( + 'Create Single-line string field "Phone number" (`phone_number`) in block model "\uD83D\uDCDE Phone Link" (`phone_link`)' + ); + await client.fields.create('C5fWG5CYRJ69oqaP6CjYdA', { + id: 'bfnOOp5cSM-x8S5RKEpKsw', + label: 'Phone number', + field_type: 'string', + api_key: 'phone_number', + hint: 'Best to use international notation: +31 20 2610954', + validators: { required: {} }, + appearance: { + addons: [], + editor: 'single_line', + parameters: { heading: false, placeholder: null }, + }, + default_value: '', + }); + + console.log( + 'Create Single-line string field "Action" (`action`) in block model "\uD83D\uDCDE Phone Link" (`phone_link`)' + ); + await client.fields.create('C5fWG5CYRJ69oqaP6CjYdA', { + id: 'ZbVIU9fdQgG8IFcEqIQ54A', + label: 'Action', + field_type: 'string', + api_key: 'action', + validators: { required: {}, enum: { values: ['call', 'sms', 'whatsapp'] } }, + appearance: { + addons: [ + { + id: 'Srdwo4YOREmRtvMAV2otlQ', + parameters: { + dependencies: + '{\n "sms": [\n "text"\n ],\n "whatsapp": [\n "text"\n ]\n}', + }, + }, + ], + editor: 'string_select', + parameters: { + options: [ + { hint: '', label: 'Call', value: 'call' }, + { hint: '', label: 'Text (sms)', value: 'sms' }, + { hint: '', label: 'WhatsApp', value: 'whatsapp' }, + ], + }, + }, + default_value: 'call', + }); + + console.log( + 'Create Multiple-paragraph text field "Text" (`text`) in block model "\uD83D\uDCDE Phone Link" (`phone_link`)' + ); + await client.fields.create('C5fWG5CYRJ69oqaP6CjYdA', { + id: 'FKNWfZ5FS-KwBcWn9H8C7A', + label: 'Text', + field_type: 'text', + api_key: 'text', + validators: { sanitized_html: { sanitize_before_validation: true } }, + appearance: { + addons: [], + editor: 'textarea', + parameters: { placeholder: null }, + type: 'textarea', + }, + default_value: '', + }); + + console.log( + 'Create Single-line string field "Style" (`style`) in block model "\uD83D\uDCDE Phone Link" (`phone_link`)' + ); + await client.fields.create('C5fWG5CYRJ69oqaP6CjYdA', { + id: 'GnHv18BPRyCsFsCAGmX0cQ', + ...actionStyleField, + }); + + console.log( + 'Create Single-line string field "Title" (`title`) in block model "\uD83D\uDCE7 Email Link" (`email_link`)' + ); + await client.fields.create('b90_c2zeS6auRELEzZHNcA', { + id: 'RM3FgSTnT4W5lYs16ndS9Q', + label: 'Title', + field_type: 'string', + api_key: 'title', + validators: { required: {} }, + appearance: { + addons: [], + editor: 'single_line', + parameters: { heading: false, placeholder: null }, + }, + default_value: '', + }); + + console.log( + 'Create Single-line string field "Email address" (`email_address`) in block model "\uD83D\uDCE7 Email Link" (`email_link`)' + ); + await client.fields.create('b90_c2zeS6auRELEzZHNcA', { + id: 'VpbcpEhCS5OjLjrdUU8Z6w', + label: 'Email address', + field_type: 'string', + api_key: 'email_address', + validators: { required: {}, format: { predefined_pattern: 'email' } }, + appearance: { + addons: [], + editor: 'single_line', + parameters: { heading: false, placeholder: null }, + }, + default_value: '', + }); + + console.log( + 'Create Single-line string field "Email Subject" (`email_subject`) in block model "\uD83D\uDCE7 Email Link" (`email_link`)' + ); + await client.fields.create('b90_c2zeS6auRELEzZHNcA', { + id: 'LMloAtp6SxOTDuaxCQ7L9g', + label: 'Email Subject', + field_type: 'string', + api_key: 'email_subject', + appearance: { + addons: [], + editor: 'single_line', + parameters: { heading: false, placeholder: null }, + }, + default_value: '', + }); + + console.log( + 'Create Multiple-paragraph text field "Email Body" (`email_body`) in block model "\uD83D\uDCE7 Email Link" (`email_link`)' + ); + await client.fields.create('b90_c2zeS6auRELEzZHNcA', { + id: 'DvV-XIMvT-eioHVaY6AOeQ', + label: 'Email Body', + field_type: 'text', + api_key: 'email_body', + appearance: { + addons: [], + editor: 'textarea', + parameters: { placeholder: null }, + type: 'textarea', + }, + default_value: '', + }); + + console.log( + 'Create Single-line string field "Style" (`style`) in block model "\uD83D\uDCE7 Email Link" (`email_link`)' + ); + await client.fields.create('b90_c2zeS6auRELEzZHNcA', { + id: 'OAAORe89QV-DoOO1GfG5Jw', + ...actionStyleField, + }); + + console.log('Update existing fields/fieldsets'); + + console.log( + 'Update Modular Content (Multiple blocks) field "Items" (`items`) in block model "\uD83C\uDF9B\uFE0F Action Block" (`action_block`)' + ); + await client.fields.update('dAUckF8qR0edf_f7zam6hA', { + validators: { + rich_text_blocks: { + item_types: [ + 'C5fWG5CYRJ69oqaP6CjYdA', + 'GWnhoQDqQoGJj4-sQTVttw', + 'Yk1ge9eTTf25Iwph1Dx3_g', + 'b90_c2zeS6auRELEzZHNcA', + ], + }, + size: { min: 1 }, + }, + }); +} diff --git a/src/blocks/ActionBlock/ActionBlock.astro b/src/blocks/ActionBlock/ActionBlock.astro index ecd9afd..69f58d1 100644 --- a/src/blocks/ActionBlock/ActionBlock.astro +++ b/src/blocks/ActionBlock/ActionBlock.astro @@ -2,6 +2,7 @@ import type { ActionBlockFragment } from '@lib/datocms/types'; import Link from '@components/Link/Link.astro'; import LinkToRecord from '@components/LinkToRecord/LinkToRecord.astro'; +import EmailLink from './EmailLink.astro'; import PhoneLink from './PhoneLink.astro'; export interface Props { @@ -30,6 +31,15 @@ const actionClassList = (style: string) => ['action', `action--${style}`]; > {item.title} + ) : item.__typename === 'EmailLinkRecord' ? ( + + {item.title} + ) : item.__typename === 'PhoneLinkRecord' ? ( ; +export type Props = HTMLAttributes<'a'> & EmailLinkProps; +const { emailAddress, emailSubject, emailBody, ...props } = Astro.props; + +const getHref = ({ emailAddress, emailSubject, emailBody }: EmailLinkProps) => { + const url = new URL(`mailto:${emailAddress}`); + if (emailSubject) url.searchParams.set('subject', emailSubject); + if (emailBody) url.searchParams.set('body', emailBody); + return url.href; +}; + +const href = getHref({ emailAddress, emailSubject, emailBody }); +--- + + diff --git a/src/blocks/ActionBlock/EmailLink.fragment.graphql b/src/blocks/ActionBlock/EmailLink.fragment.graphql new file mode 100644 index 0000000..c9ee979 --- /dev/null +++ b/src/blocks/ActionBlock/EmailLink.fragment.graphql @@ -0,0 +1,9 @@ +fragment EmailLink on EmailLinkRecord { + __typename + id + title + emailAddress + emailSubject + emailBody + style +} From eeb8b8f088fb38e776a5429e08fe98bc528a8e20 Mon Sep 17 00:00:00 2001 From: Jasper Moelker Date: Sat, 28 Dec 2024 20:52:59 +0100 Subject: [PATCH 4/4] refactor: remove (useless) phone package --- package-lock.json | 10 ---------- package.json | 1 - src/blocks/ActionBlock/PhoneLink.astro | 5 +---- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index b49672b..47cbb2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,6 @@ "jiti": "^1.20.0", "nanostores": "^0.9.5", "oembed-providers": "^1.0.20230906", - "phone": "^3.1.56", "pretty-bytes": "^6.1.1", "promise-all-props": "^3.0.0", "regexparam": "^3.0.0", @@ -15536,15 +15535,6 @@ "node": "*" } }, - "node_modules/phone": { - "version": "3.1.56", - "resolved": "https://registry.npmjs.org/phone/-/phone-3.1.56.tgz", - "integrity": "sha512-KF2asNQQqLnsutv/DQLRhiOCLkmu+0kspCc1L+EgPT688JEhkyw6hbr9U4ROvMSI6/xBw5TtdCeLSWJkaUWjyw==", - "license": "MIT", - "engines": { - "node": ">=12" - } - }, "node_modules/picocolors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", diff --git a/package.json b/package.json index 91bdbfe..81690b4 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,6 @@ "jiti": "^1.20.0", "nanostores": "^0.9.5", "oembed-providers": "^1.0.20230906", - "phone": "^3.1.56", "pretty-bytes": "^6.1.1", "promise-all-props": "^3.0.0", "regexparam": "^3.0.0", diff --git a/src/blocks/ActionBlock/PhoneLink.astro b/src/blocks/ActionBlock/PhoneLink.astro index 3b7bc3a..67eba7c 100644 --- a/src/blocks/ActionBlock/PhoneLink.astro +++ b/src/blocks/ActionBlock/PhoneLink.astro @@ -1,7 +1,6 @@ --- import type { HTMLAttributes } from 'astro/types'; import type { PhoneLinkFragment } from '@lib/datocms/types'; -import { phone } from 'phone'; type PhoneLinkProps = Pick< PhoneLinkFragment, @@ -11,9 +10,7 @@ export type Props = HTMLAttributes<'a'> & PhoneLinkProps; const { action, phoneNumber, text, ...props } = Astro.props; const formatPhoneNumber = (phoneNumber: string) => { - const output = phone(phoneNumber); - // console.log(output); - return output.isValid ? output.phoneNumber : phoneNumber.replace(/\s/g, ''); + return phoneNumber.replace(/\s/g, ''); }; const getHref = ({ action, phoneNumber, text }: PhoneLinkProps) => {