Skip to content

Commit

Permalink
Feature: add Campaign Cover Block (#7701)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshuaHungDinh authored Feb 2, 2025
1 parent a9ba5df commit 22bbb3b
Show file tree
Hide file tree
Showing 11 changed files with 386 additions and 14 deletions.
16 changes: 16 additions & 0 deletions src/Campaigns/Blocks/CampaignCover/Icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {Path, SVG} from "@wordpress/components";

export function GalleryIcon() {
return (
<SVG
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
aria-hidden="true"
focusable="false"
>
<Path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM5 4.5h14c.3 0 .5.2.5.5v8.4l-3-2.9c-.3-.3-.8-.3-1 0L11.9 14 9 12c-.3-.2-.6-.2-.8 0l-3.6 2.6V5c-.1-.3.1-.5.4-.5zm14 15H5c-.3 0-.5-.2-.5-.5v-2.4l4.1-3 3 1.9c.3.2.7.2.9-.1L16 12l3.5 3.4V19c0 .3-.2.5-.5.5z"></Path>
</SVG>
);
}
88 changes: 88 additions & 0 deletions src/Campaigns/Blocks/CampaignCover/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "givewp/campaign-cover-block",
"version": "1.0.0",
"title": "Campaign Cover",
"category": "give",
"description": "Displays the cover image of the campaign.",
"attributes": {
"campaignId": {
"type": "integer"
},
"alt": {
"type": "string"
},
"width": {
"type": "number",
"default": 645
},
"height": {
"type": "number",
"default": 865
},
"align": {
"type": "string",
"default": ""
}
},
"supports": {
"align": [
"wide",
"full",
"left",
"center",
"right"
],
"filter": {
"duotone": true
},
"selectors": {
"filter": {
"duotone": ".wp-block-givewp-campaign-cover-block img"
}
},
"anchor": true,
"className": true,
"splitting": true,
"__experimentalBorder": {
"color": true,
"radius": true,
"style": true,
"width": true
},
"color": {
"gradients": true,
"link": true,
"__experimentalDefaultControls": {
"background": true,
"text": true
}
},
"spacing": {
"margin": true,
"padding": true,
"__experimentalDefaultControls": {
"margin": false,
"padding": false
}
},
"typography": {
"fontSize": true,
"lineHeight": true,
"__experimentalFontFamily": true,
"__experimentalFontStyle": true,
"__experimentalFontWeight": true,
"__experimentalLetterSpacing": true,
"__experimentalTextTransform": true,
"__experimentalTextDecoration": true,
"__experimentalWritingMode": true,
"__experimentalDefaultControls": {
"fontSize": true
}
}
},
"textdomain": "give",
"render": "file:./render.php",
"style": "file:./style.css"
}
143 changes: 143 additions & 0 deletions src/Campaigns/Blocks/CampaignCover/edit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import {InspectorControls, useBlockProps} from '@wordpress/block-editor';
import {__} from '@wordpress/i18n';
import {useSelect} from '@wordpress/data';
import {external} from '@wordpress/icons';
import {BaseControl, Icon, PanelBody, Placeholder, ResizableBox, TextareaControl} from '@wordpress/components';
import {BlockEditProps} from '@wordpress/blocks';
import {CampaignSelector} from '../shared/components/CampaignSelector';
import useCampaign from '../shared/hooks/useCampaign';
import {GalleryIcon} from "./Icon";

import './editor.scss';

interface EditProps extends BlockEditProps<{
campaignId: number;
alt: string;
width: number;
height: number;
align: string;
}> {
toggleSelection: (isSelected: boolean) => void;
}

export default function Edit({attributes, setAttributes, toggleSelection}: EditProps) {
const blockProps = useBlockProps();
const {campaign, hasResolved} = useCampaign(attributes.campaignId);

const adminBaseUrl = useSelect(
// @ts-ignore
(select) => select('core').getSite()?.url + '/wp-admin/edit.php?post_type=give_forms&page=give-campaigns',
[]
);
const editCampaignUrl = `${adminBaseUrl}&id=${attributes.campaignId}&tab=settings`;

const handleResizeStop = (event: MouseEvent | TouchEvent, direction, refToElement: HTMLDivElement, delta: {
height: number,
width: number
}) => {
setAttributes({
height: attributes.height + delta.height,
width: attributes.width + delta.width,
});
toggleSelection(true);
};

const isSizeAligned = attributes.align === 'full' || attributes.align === 'wide';

return (
<figure {...blockProps}>
<CampaignSelector attributes={attributes} setAttributes={setAttributes}>
{hasResolved && !campaign?.image && (
<Placeholder
icon={<GalleryIcon />}
label={__('Campaign Cover Image', 'give')}
instructions={__('Upload a cover image for your campaign.', 'give')}
/>

)}

{hasResolved && campaign?.image &&
(!isSizeAligned ? (
<ResizableBox
size={{
width: attributes.width,
height: attributes.height,
}}
/* max-width of the block editor with alignment='none' */
maxWidth={645}
style={{
position: 'relative',
userSelect: 'auto',
display: 'block',
boxSizing: 'border-box',
width: 'auto',
height: 'auto',
}}
onResizeStart={() => {
toggleSelection(false);
}}
onResizeStop={handleResizeStop}
enable={{
bottom: true,
right: true,
bottomRight: false,
top: false,
left: false,
topLeft: false,
topRight: true,
bottomLeft: false,
}}
>
<img
className={'givewp-campaign-cover-block-preview__image'}
src={campaign?.image}
alt={attributes.alt ?? __('Campaign Image', 'give')}
style={{width: '100%', height: '100%'}}
/>
</ResizableBox>
) : (
<img
className={'givewp-campaign-cover-block-preview__image'}
src={campaign?.image}
alt={attributes.alt ?? __('Campaign Image', 'give')}
style={{width: '100%', height: '100%'}}
/>
))}
</CampaignSelector>

{hasResolved && campaign && (
<InspectorControls>
<PanelBody title="Settings" initialOpen={true}>
<BaseControl label={__('Cover', 'give')} id="givewp-campaign-cover-block__title-field">
{campaign?.image && (
<img
className={'givewp-campaign-cover-block__image'}
src={campaign?.image}
alt={attributes.alt ?? __('Campaign Cover image', 'give')}
/>
)}
<p className={'givewp-campaign-cover-block__help-text'}>
{__('Shows the cover image of the campaign.', 'give')}
</p>
<a
href={editCampaignUrl}
target="_blank"
rel="noopener noreferrer"
className="givewp-campaign-cover-block__edit-campaign-link"
aria-label={__('Edit campaign settings in a new tab', 'give')}
>
{__('Change campaign cover', 'give')}
<Icon icon={external} />
</a>
</BaseControl>
<TextareaControl
label={__('Alternative text', 'give')}
value={attributes.alt}
onChange={(value: string) => setAttributes({alt: value})}
/>
</PanelBody>
</InspectorControls>
)}
</figure>
);
}
61 changes: 61 additions & 0 deletions src/Campaigns/Blocks/CampaignCover/editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
.givewp-campaign-cover-block {
&__button {
display: flex;
align-items: center;
justify-content: center;
min-height: 32px;
width: 100%;
margin-bottom: .5rem;
color: #2271b1;
border: 1px solid #2271b1;
border-radius: 2px;
}

&__image {
flex-grow: 1;
display: flex;
max-height: 4.44rem;
width: 100%;
object-fit: cover;
margin-bottom: .5rem;
border-radius: 2px;
}

&__help-text {
font-size: 0.75rem;
font-weight: normal;
font-stretch: normal;
font-style: normal;
line-height: 1.4;
letter-spacing: normal;
text-align: left;
color: #4b5563;
}

&__edit-campaign-link {
display: inline-flex;
align-items: center;
gap: 0.125rem;
font-size: 0.75rem;
font-weight: normal;
font-stretch: normal;
font-style: normal;
line-height: 1.4;

svg {
fill: currentColor;
height: 1.25rem;
width: 1.25rem;
}
}
}

.givewp-campaign-cover-block-preview {
&__image {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
}
14 changes: 14 additions & 0 deletions src/Campaigns/Blocks/CampaignCover/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import metadata from './block.json';
import Edit from './edit';
import initBlock from '../shared/utils/init-block';
import {GalleryIcon} from './Icon';

const {name} = metadata;

export {metadata, name};
export const settings = {
edit: Edit,
icon: <GalleryIcon />,
};

export const init = () => initBlock({name, metadata, settings});
42 changes: 42 additions & 0 deletions src/Campaigns/Blocks/CampaignCover/render.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

use Give\Campaigns\Models\Campaign;
use Give\Campaigns\Repositories\CampaignRepository;

if ( ! isset($attributes['campaignId'])) {
return;
}

/** @var Campaign $campaign */
$campaign = give(CampaignRepository::class)->getById($attributes['campaignId']);

if ( ! $campaign) {
return;
}

$campaignMediaSetting = $campaign->image;

$altText = $attributes['alt'] ?? __('Campaign cover image', 'give');
$alignment = isset($attributes['align']) ? 'align' . $attributes['align'] : '';

// Only assign width and height if the alignment is NOT "full" or "wide"
if ($attributes['align'] !== 'full' && $attributes['align'] !== 'wide') {
$width = isset($attributes['width']) ? $attributes['width'] : '100%';
$height = isset($attributes['height']) ? $attributes['height'] : '100%';
} else {
$width = 'auto';
$height = 'auto';
}
?>


<figure class="wp-block-givewp-campaign-cover-block <?php echo esc_attr($alignment) ?>">
<img
src="<?php echo esc_url($campaign->image); ?>"
alt="<?php echo esc_attr($altText); ?>"
style="
width:<?php echo $width ?>px;
height: <?php echo $height ?>px;
border-radius: 8px;"
/>
</figure>
3 changes: 2 additions & 1 deletion src/Campaigns/Blocks/blocks.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as campaignTitleBlock from './CampaignTitleBlock';
import * as campaignCover from './CampaignCover';

const getAllBlocks = () => {
return [campaignTitleBlock];
return [campaignTitleBlock, campaignCover];
};

getAllBlocks().forEach((block) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,10 @@ export default () => {

<div className={styles.sectionField}>
<div className={styles.sectionSubtitle}>
{__('Add a cover image or video for your campaign.', 'give')}
{__('Add a cover image for your campaign.', 'give')}
</div>
<div className={styles.sectionFieldDescription}>
{__('Upload an image or video to represent and inspire your campaign.', 'give')}
{__('Upload an image to represent and inspire your campaign.', 'give')}
</div>
<div className={styles.upload}>
<Upload
Expand Down
Loading

0 comments on commit 22bbb3b

Please sign in to comment.