Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: add Campaign Cover Block #7701

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading