Skip to content

Feature/cms 1411 thumb alignment setting for card view designers #17193

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

Open
wants to merge 15 commits into
base: 5.8
Choose a base branch
from
Open
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
8 changes: 8 additions & 0 deletions src/base/Element.php
Original file line number Diff line number Diff line change
Expand Up @@ -4293,6 +4293,14 @@ public function getThumbHtml(int $size): ?string
return null;
}

/**
* @inheritdoc
*/
public function getThumbAlignment(): string
{
return $this->getFieldLayout()?->getCardThumbAlignment() ?? 'end';
}

/**
* Returns the URL to the element’s thumbnail, if it has one.
*
Expand Down
8 changes: 8 additions & 0 deletions src/base/Thumbable.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,12 @@ interface Thumbable
* @return string|null
*/
public function getThumbHtml(int $size): ?string;

/**
* Returns the alignment in which the component's thumbnail should show.
*
* @return string
* @since 5.8.0
*/
public function getThumbAlignment(): string;
}
3 changes: 3 additions & 0 deletions src/controllers/FieldsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ public function actionRenderCardPreview()
$fieldLayoutConfig = $this->request->getRequiredBodyParam('fieldLayoutConfig');
$cardElements = $this->request->getRequiredBodyParam('cardElements');
$showThumb = $this->request->getBodyParam('showThumb', false);
$thumbAlignment = $this->request->getBodyParam('thumbAlignment', false);

if (!isset($fieldLayoutConfig['id'])) {
$fieldLayout = Craft::createObject([
Expand All @@ -630,6 +631,8 @@ public function actionRenderCardPreview()
array_column($cardElements, 'value')
); // this fully takes care of attributes, but not fields

$fieldLayout->setCardThumbAlignment($thumbAlignment);

return $this->asJson([
'previewHtml' => Cp::cardPreviewHtml($fieldLayout, $cardElements, $showThumb),
]);
Expand Down
134 changes: 130 additions & 4 deletions src/helpers/Cp.php
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,15 @@ public static function elementCardHtml(ElementInterface $element, array $config
$classes[] = 'error';
}

$thumb = $element->getThumbHtml(120);
if ($thumb) {
$thumbAlignment = $element->getThumbAlignment();

if ($thumbAlignment) {
$classes[] = 'thumb-' . $thumbAlignment;
}
}

$attributes = ArrayHelper::merge(
self::baseElementAttributes($element, $config),
[
Expand Down Expand Up @@ -732,7 +741,6 @@ public static function elementCardHtml(ElementInterface $element, array $config
Html::endTag('div');
}

$thumb = $element->getThumbHtml(120);
$icon = $element instanceof Iconic ? $element->getIcon() : null;
$title = $element->getCardTitle();

Expand Down Expand Up @@ -2001,7 +2009,7 @@ public static function rangeHtml(array $config): string
}

/**
* Renders a lightswitch field’s HTML.
* Renders a range field’s HTML.
*
* @param array $config
* @return string
Expand All @@ -2014,6 +2022,33 @@ public static function rangeFieldHtml(array $config): string
return static::fieldHtml('template:_includes/forms/range.twig', $config);
}

/**
* Renders a button group input’s HTML.
*
* @param array $config
* @return string
* @throws TemplateLoaderException
* @since 5.8.0
*/
public static function buttonGroupHtml(array $config): string
{
return static::renderTemplate('_includes/forms/buttonGroup.twig', $config);
}

/**
* Renders a button group field’s HTML.
*
* @param array $config
* @return string
* @throws TemplateLoaderException
* @since 5.8.0
*/
public static function buttonGroupFieldHtml(array $config): string
{
$config['id'] ??= 'buttongroup' . mt_rand();
return static::fieldHtml('template:_includes/forms/buttonGroup.twig', $config);
}

/**
* Renders a money input’s HTML.
*
Expand Down Expand Up @@ -2745,9 +2780,96 @@ public static function cardViewDesignerHtml(FieldLayout $fieldLayout, array $con
Html::endTag('div') . // .cvd-preview-container
Html::endTag('div') . // .cvd-preview
Html::endTag('div') . // .cvd-container
self::_getThumbManagementHtml($fieldLayout, $config) .
Html::endTag('div'); // .card-view-designer
}

/**
* Return HTML for managing thumbnail provider and position.
*
* @param FieldLayout $fieldLayout
* @param array $config
* @return string
* @throws TemplateLoaderException
*/
private static function _getThumbManagementHtml(FieldLayout $fieldLayout, array $config): string
{
$readOnly = isset($config['config']['disabled']) && $config['config']['disabled'];
if ((new ($fieldLayout['type']))->hasThumbs()) {
$options = [
['label' => Craft::t('app', 'Default'), 'value' => '__default__'],
];
} else {
$options = [
['label' => Craft::t('app', 'No thumbnail'), 'value' => '__none__'],
];
}
$elementThumbnail = $fieldLayout->getThumbField()?->uid;
$thumbnailAlignment = $fieldLayout->getCardThumbAlignment();

$thumbableElements = array_filter(
$fieldLayout->getAllElements(),
fn($element) => $element instanceof BaseField && $element->thumbable()
);

foreach ($thumbableElements as $thumbableElement) {
$options[] = ['label' => $thumbableElement->label(), 'value' => $thumbableElement->uid];
}

$thumbHtml = Html::beginTag('div', ['class' => 'thumb-management']) .
Html::tag('h2', Craft::t('app', 'Manage element thumbnails'), ['class' => 'visually-hidden']) .
Html::beginTag('div', ['class' => 'flex flex-nowrap']);

// dropdown field that contains all thumbable fields + 'No thumbnail' option
$thumbHtml .= self::selectFieldHtml([
'label' => Craft::t('app', 'Use for element thumbnails'),
'id' => 'thumb-source',
'name' => 'thumbSource',
'options' => $options,
'value' => $elementThumbnail,
'disabled' => $readOnly,
]);

// radio button switch that lets you choose whether the thumb alignment should be start or end
$orientation = Craft::$app->getLocale()->getOrientation();
$thumbHtml .= self::buttonGroupFieldHtml([
'label' => Craft::t('app', 'Thumbnail alignment'),
'id' => 'thumb-alignment',
'fieldClass' => $elementThumbnail === null ? 'hidden' : false,
'name' => 'thumbAlignment',
'options' => [
[
'icon' => $orientation == 'ltr' ? 'slideout-left' : 'slideout-right',
'value' => 'start',
'attributes' => [
'title' => $orientation == 'ltr' ? Craft::t('app', 'Left') : Craft::t('app', 'Right'),
'aria' => [
'label' => $orientation == 'ltr' ? Craft::t('app', 'Left') : Craft::t('app', 'Right'),
],
],
],
[
'icon' => $orientation == 'ltr' ? 'slideout-right' : 'slideout-left',
'value' => 'end',
'attributes' => [
'title' => $orientation == 'ltr' ? Craft::t('app', 'Right') : Craft::t('app', 'Left'),
'aria' => [
'label' => $orientation == 'ltr' ? Craft::t('app', 'Right') : Craft::t('app', 'Left'),
],
],
],
],
'value' => $thumbnailAlignment,
'disabled' => $readOnly,
]);


$thumbHtml .= Html::endTag('div') . // .flex
Html::endTag('div'); // .thumb-management

return $thumbHtml;
}

/**
* Returns HTML for the card preview based on selected fields and attributes.
*
Expand All @@ -2758,6 +2880,9 @@ public static function cardViewDesignerHtml(FieldLayout $fieldLayout, array $con
*/
public static function cardPreviewHtml(FieldLayout $fieldLayout, array $cardElements = [], $showThumb = false): string
{
$hasThumb = $showThumb ?? $fieldLayout->getThumbField() !== null ? true : (new ($fieldLayout['type']))->hasThumbs();
$thumbAlignment = $fieldLayout->getCardThumbAlignment();

// get heading
$heading = Html::tag('craft-element-label',
Html::tag('a', Html::tag('span', Craft::t('app', 'Title')), [
Expand All @@ -2777,7 +2902,7 @@ public static function cardPreviewHtml(FieldLayout $fieldLayout, array $cardElem

$previewHtml =
Html::beginTag('div', [
'class' => ['element', 'card'],
'class' => ['element', 'card', $hasThumb ? 'thumb-' . $thumbAlignment : null],
]);

$previewHtml .=
Expand Down Expand Up @@ -2816,7 +2941,7 @@ public static function cardPreviewHtml(FieldLayout $fieldLayout, array $cardElem
Html::endTag('div'); // .card-content

// get thumb placeholder
if ($showThumb ?? $fieldLayout->getThumbField() !== null) {
if ($hasThumb) {
$previewThumb = Html::tag('div',
Html::tag('div', Cp::iconSvg('image'), ['class' => 'cp-icon']),
['class' => 'cvd-thumbnail']
Expand Down Expand Up @@ -2892,6 +3017,7 @@ public static function fieldLayoutDesignerHtml(FieldLayout $fieldLayout, array $
'customizableTabs' => $config['customizableTabs'],
'customizableUi' => $config['customizableUi'],
'withCardViewDesigner' => $config['withCardViewDesigner'] ?? false,
'alwaysShowThumbAlignmentBtns' => (new ($fieldLayout['type']))->hasThumbs(),
'readOnly' => $readOnly,
]);
$namespacedId = $view->namespaceInputId($config['id']);
Expand Down
46 changes: 46 additions & 0 deletions src/models/FieldLayout.php
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,13 @@ public static function createFromConfig(array $config): self
*/
private array $_cardView;

/**
* @var string
* @see getCardThumbAlignment()
* @see setCardThumbAlignment()
*/
private string $_cardThumbAlignment;

/**
* @inheritdoc
*/
Expand All @@ -276,6 +283,10 @@ public function init(): void
$this->setCardView([]);
}
}

if (!isset($this->_cardThumbAlignment)) {
$this->setCardThumbAlignment();
}
}

/**
Expand Down Expand Up @@ -422,6 +433,38 @@ public function setCardView(?array $items): void
$this->reset();
}

/**
* Returns the layout’s card view thumbnail alignment.
*
* @return string The layout’s card view thumbnail alignment.
* @since 5.8.0
*/
public function getCardThumbAlignment(): string
{
if (!isset($this->_cardThumbAlignment)) {
$this->setCardThumbAlignment();
}

return $this->_cardThumbAlignment;
}

/**
* Sets the layout’s card view thumbnail alignment.
*
* @param string|null $alignment The alignment of the card view thumbnail.
* @since 5.8.0
*/
public function setCardThumbAlignment(?string $alignment = null): void
{
$validOptions = ['start', 'end'];

if (!in_array($alignment, $validOptions)) {
$alignment = null;
}

$this->_cardThumbAlignment = $alignment ?? 'end';
}

/**
* Returns the available fields, grouped by field group name.
*
Expand Down Expand Up @@ -587,14 +630,17 @@ public function getConfig(): ?array
));

$cardViewConfig = $this->getCardView();
$cardThumbAlignment = $this->getCardThumbAlignment();

if (empty($tabConfigs) && empty($cardViewConfig)) {
// no point bothering with the thumb alignment if we don't have the card view
return null;
}

return [
'tabs' => $tabConfigs,
'cardView' => $cardViewConfig,
'cardThumbAlignment' => $cardThumbAlignment,
];
}

Expand Down
1 change: 1 addition & 0 deletions src/services/Fields.php
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,7 @@ public function assembleLayoutFromPost(?string $namespace = null): FieldLayout
$config = JsonHelper::decode(Craft::$app->getRequest()->getBodyParam($paramPrefix . 'fieldLayout'));
$cardView = Craft::$app->getRequest()->getBodyParam($paramPrefix . 'cardView');
$config['cardView'] = empty($cardView) ? null : $cardView;
$config['cardThumbAlignment'] = Craft::$app->getRequest()->getBodyParam($paramPrefix . 'thumbAlignment');
$layout = $this->createLayout($config);

// Make sure all the elements have a dateAdded value set
Expand Down
6 changes: 5 additions & 1 deletion src/templates/_includes/forms/button.twig
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@
{% set icon = icon ?? null %}
{% set label = label ?? null %}
{% set labelHtml = labelHtml ?? null %}

{# the "disabled" class takes care of disabling the button,
but the "read-only" class is needed so that it is allowed to have custom tabindex attribute #}
{% set attributes = {
type: type ?? 'button',
id: id ?? false,
class: (class ?? [])|explodeClass|merge([
'btn',
not (icon or label or labelHtml) ? 'btn-empty' : null,
(disabled ?? false) ? 'disabled',
(disabled ?? readOnly ?? false) ? 'disabled',
(readOnly ?? false) ? 'read-only',
]|filter),
data: {
'busy-message': busyMessage,
Expand Down
3 changes: 3 additions & 0 deletions src/templates/_includes/forms/buttonGroup.twig
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@
data: {
value: option.value ?? null,
},
tabindex: disabled ? '-1' : '0',
}|merge(option.attributes ?? {}, recursive=true),
readOnly: disabled,
}) }}
{% endfor %}
{% endtag %}
Expand All @@ -54,6 +56,7 @@
onChange: (selectedOption) => {
$('#{{ inputId|namespaceInputId }}').val(selectedOption.data('value'));
},
readOnly: {{ disabled ? 1 : 0 }}
});
})();
{% endjs %}
Expand Down
3 changes: 3 additions & 0 deletions src/translations/en/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,7 @@
'Make sure you’ve followed the <a href="{url}" target="_blank">Environment Setup</a> instructions before applying project config YAML changes.' => 'Make sure you’ve followed the <a href="{url}" target="_blank">Environment Setup</a> instructions before applying project config YAML changes.',
'Make this the primary site' => 'Make this the primary site',
'Manage categories' => 'Manage categories',
'Manage element thumbnails' => 'Manage element thumbnails',
'Manage your Craft Console account' => 'Manage your Craft Console account',
'Manipulated SVG image rasterizing is unreliable. See \\craft\\services\\Images::loadImage()' => 'Manipulated SVG image rasterizing is unreliable. See \\craft\\services\\Images::loadImage()',
'Matrix' => 'Matrix',
Expand Down Expand Up @@ -1115,6 +1116,7 @@
'No sources exist yet.' => 'No sources exist yet.',
'No tag groups exist yet.' => 'No tag groups exist yet.',
'No template path has been chosen yet.' => 'No template path has been chosen yet.',
'No thumbnail' => 'No thumbnail',
'No usages' => 'No usages',
'No user groups exist yet.' => 'No user groups exist yet.',
'No volumes exist yet.' => 'No volumes exist yet.',
Expand Down Expand Up @@ -1793,6 +1795,7 @@
'This {type} doesn’t have revisions.' => 'This {type} doesn’t have revisions.',
'This {type} has been edited.' => 'This {type} has been edited.',
'This {type} has been updated.' => 'This {type} has been updated.',
'Thumbnail alignment' => 'Thumbnail alignment',
'Time Zone' => 'Time Zone',
'Time fields are better suited for managing Time-only values.' => 'Time fields are better suited for managing Time-only values.',
'Time to reserve' => 'Time to reserve',
Expand Down
2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/css/cp.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/css/cp.css.map

Large diffs are not rendered by default.

Loading
Loading