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

fix(atomic): atomic-product layout in grid mode consistent on all screen sizes #4527

Merged
merged 14 commits into from
Oct 31, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,21 @@
}
}
&.display-grid {
&.image-large,
&.image-small,
&.image-icon,
&.image-none {
atomic-product-section-name {
min-height: calc(var(--line-height) * 2);
-webkit-line-clamp: 2;
line-clamp: 2;
}
}
@screen desktop-only {
&.image-large {
atomic-product-section-children .product-child {
@mixin aspect-ratio-h 1 / 1, auto;
width: 33%;
width: 16.65%;
fpbrault marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -39,11 +49,17 @@
}

@screen mobile-only {
&.image-large,
&.image-large {
atomic-product-section-children .product-child {
@mixin aspect-ratio-h 1 / 1, auto;
width: 16.65%;
}
}
&.image-small {
atomic-product-section-children .product-child {
@mixin aspect-ratio-h 1 / 1, auto;
width: 16.65%;
max-width: 4.75rem;
}
fpbrault marked this conversation as resolved.
Show resolved Hide resolved
}

Expand All @@ -55,6 +71,38 @@
}
}
}

&.density-comfortable {
&.image-icon,
&.image-none,
&.image-small,
&.image-large {
& atomic-product-section-description {
margin-top: 1.25rem;
}
}
}
&.density-normal {
&.image-icon,
&.image-none,
&.image-small,
&.image-large {
& atomic-product-section-description {
margin-top: 0.75rem;
}
}
}

&.density-compact {
&.image-icon,
&.image-none,
&.image-small,
&.image-large {
& atomic-product-section-description {
margin-top: 0.25rem;
}
}
}
fpbrault marked this conversation as resolved.
Show resolved Hide resolved
}

&.display-list {
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,26 @@
@import '../../../../global/global.pcss';

atomic-product-children .children-container {
display: flex;
flex-wrap: wrap;
}

.display-grid {
& atomic-product-children .children-container .product-child  {
&:nth-child(n + 6) {
display: none;
}
&:nth-child(6) {
& ~ .plus-button {
display: block;
}
&:last-child ~ .plus-button {
display: none;
}
}
}
}

atomic-product-children .children-container .plus-button {
display: none;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ import {
Event,
EventEmitter,
State,
Host,
} from '@stencil/core';
import {
InitializableComponent,
InitializeBindings,
} from '../../../../utils/initialization-utils';
import {filterProtocol} from '../../../../utils/xss-utils';
import {Button} from '../../../common/button';
import {CommerceBindings} from '../../atomic-commerce-interface/atomic-commerce-interface';
import {ProductContext} from '../product-template-decorators';

Expand Down Expand Up @@ -164,10 +166,15 @@ export class AtomicProductChildren
}

return (
<div>
<Host>
{this.label.trim() !== '' && this.renderLabel()}
<div>{this.children.map((child) => this.renderChild(child))}</div>
</div>
<div class="children-container">
{this.children.map((child) => this.renderChild(child))}
<Button style="text-primary" class="product-child plus-button">
+{this.children.length - 5}
</Button>
</div>
</Host>
fpbrault marked this conversation as resolved.
Show resolved Hide resolved
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const Default: Story = {
const searchInterface = context.canvasElement.querySelector(
'atomic-commerce-interface'
);
searchInterface?.engine?.dispatch(updateQuery({query: 'kayak'}));
searchInterface?.engine?.dispatch(updateQuery({query: 'boat'}));

await searchInterface!.executeFirstRequest();
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import '../../../common/expandable-text/expandable-text.pcss';
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {ProductContext} from '../product-template-decorators';
*/
@Component({
tag: 'atomic-product-description',
styleUrl: 'atomic-product-description.pcss',
shadow: false,
})
export class AtomicProductDescription
Expand Down Expand Up @@ -118,9 +119,7 @@ export class AtomicProductDescription
showLessLabel={this.bindings.i18n.t('show-less')}
isCollapsible={this.isCollapsible}
>
<atomic-product-text field={this.field}>
{productDescription}
</atomic-product-text>
<atomic-product-text field={this.field}></atomic-product-text>
</ExpandableText>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,17 @@ test.describe('atomic-product-description', async () => {

test.describe('when description is truncated', async () => {
const truncateValues: Array<{
value: '1' | '2' | '3' | '4';
value: '1' | '4';
expectedClass: RegExp;
}> = [
{value: '1', expectedClass: /line-clamp-1/},
{value: '2', expectedClass: /line-clamp-2/},
{value: '3', expectedClass: /line-clamp-3/},
{value: '4', expectedClass: /line-clamp-4/},
];

truncateValues.forEach(({value, expectedClass}) => {
test.beforeEach(async ({productDescription}) => {
await productDescription.withLongDescription();
});
test.describe(`when truncateAfter is set to ${value}`, async () => {
test(`should truncate description after ${value} lines`, async ({
productDescription,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,19 @@ export class ProductDescriptionPageObject extends BasePageObject<'atomic-product
get showLessButton() {
return this.page.getByRole('button', {name: 'Show less'});
}

async withLongDescription() {
await this.page.route('**/commerce/v2/search', async (route) => {
const response = await route.fetch();
const body = await response.json();
body.products[0].ec_description =
'This is a long description that should be truncated'.repeat(10);
await route.fulfill({
response,
json: body,
});
});

return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import '../../../common/expandable-text/expandable-text.pcss';
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {ProductContext} from '../product-template-decorators';
*/
@Component({
tag: 'atomic-product-excerpt',
styleUrl: 'atomic-product-excerpt.pcss',
shadow: false,
})
export class AtomicProductExcerpt
Expand Down Expand Up @@ -109,9 +110,7 @@ export class AtomicProductExcerpt
showLessLabel={this.bindings.i18n.t('show-less')}
isCollapsible={this.isCollapsible}
>
<atomic-product-text field="excerpt">
{productExcerpt}
</atomic-product-text>
<atomic-product-text field="excerpt"></atomic-product-text>
</ExpandableText>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,17 @@ test.describe('atomic-product-excerpt', async () => {

test.describe('when excerpt is truncated', async () => {
const truncateValues: Array<{
value: '1' | '2' | '3' | '4';
value: '2' | '3';
expectedClass: RegExp;
}> = [
{value: '1', expectedClass: /line-clamp-1/},
{value: '2', expectedClass: /line-clamp-2/},
{value: '3', expectedClass: /line-clamp-3/},
{value: '4', expectedClass: /line-clamp-4/},
];

truncateValues.forEach(({value, expectedClass}) => {
test.beforeEach(async ({productExcerpt}) => {
await productExcerpt.withLongExcerpt();
});
test.describe(`when truncateAfter is set to ${value}`, async () => {
test(`should truncate excerpt after ${value} lines`, async ({
productExcerpt,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,19 @@ export class ProductExcerptPageObject extends BasePageObject<'atomic-product-exc
get showLessButton() {
return this.page.getByRole('button', {name: 'Show less'});
}

async withLongExcerpt() {
await this.page.route('**/commerce/v2/search', async (route) => {
const response = await route.fetch();
const body = await response.json();
body.products[0].excerpt =
'This is a long excerpt that should be truncated'.repeat(10);
await route.fulfill({
response,
json: body,
});
});

return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.display-grid {
fpbrault marked this conversation as resolved.
Show resolved Hide resolved
& atomic-product-price {
display: flex;
flex-wrap: wrap;
flex-direction: column;

& .original-price {
line-height: 1;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
Context,
ContextState,
} from '@coveo/headless/commerce';
import {Component, h} from '@stencil/core';
import {Component, h, Host} from '@stencil/core';
import {
BindStateToController,
InitializableComponent,
Expand All @@ -21,6 +21,7 @@ import {parseValue} from '../product-utils';
*/
@Component({
tag: 'atomic-product-price',
styleUrl: 'atomic-product-price.pcss',
shadow: false,
})
export class AtomicProductPrice
Expand Down Expand Up @@ -82,18 +83,22 @@ export class AtomicProductPrice
: null;

return (
<div class="flex flex-wrap">
<Host class="flex flex-wrap gap-1">
<div
class={`mx-1 truncate break-keep ${this.hasPromotionalPrice && 'text-error'}`}
class={`truncate break-keep ${this.hasPromotionalPrice && 'text-error'}`}
>
{mainPrice}
</div>
{originalPrice && (
<div class="mx-1 truncate break-keep text-xl line-through">
{originalPrice}
</div>
)}
</div>

<div
class={
'original-price truncate break-keep text-xl line-through ' +
(!originalPrice && ' invisible')
}
>
{originalPrice ?? '​'}
</div>
</Host>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.expandable-text {
line-height: var(--line-height);
}

.min-lines-1 {
min-height: calc(var(--line-height) * 1);
}

.min-lines-2 {
min-height: calc(var(--line-height) * 2);
}

.min-lines-3 {
min-height: calc(var(--line-height) * 3);
}

.min-lines-4 {
min-height: calc(var(--line-height) * 4);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,19 @@ const renderShowHideButton = (
showMoreLabel: string,
showLessLabel: string
) => {
let buttonClass = 'expandable-text-button p-1 text-xs';
if (!isTruncated && !isExpanded) {
return null;
}

if (!isCollapsible && !isTruncated && isExpanded) {
return null;
buttonClass += ' invisible';
} else if (!isCollapsible && !isTruncated && isExpanded) {
buttonClass += ' hidden';
}

const label = isExpanded ? showLessLabel : showMoreLabel;

return (
<Button
style="text-primary"
class="expandable-text-button p-1 text-xs"
class={buttonClass}
title={label}
onClick={onToggleExpand}
>
Expand Down Expand Up @@ -76,7 +75,7 @@ export const ExpandableText: FunctionalComponent<ExpandableTextProps> = (
<div class="flex flex-col items-start">
<div
part="expandable-text"
class={`expandable-text ${!isExpanded ? getLineClampClass(truncateAfter) : ''}`}
class={`expandable-text ${!isExpanded ? getLineClampClass(truncateAfter) : ''} min-lines-${truncateAfter}`}
>
{children}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@
grid-template-columns: repeat(3, 1fr);
}
@media (min-width: 1024px) {
grid-template-columns: repeat(3, 1fr);
}
@media (min-width: 1280px) {
grid-template-columns: repeat(4, 1fr);
}
fpbrault marked this conversation as resolved.
Show resolved Hide resolved
}
Expand Down
Loading
Loading