Skip to content
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
5 changes: 5 additions & 0 deletions .changeset/pretty-bibles-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@youversion/platform-react-ui": minor
---

Center card content within full-width BibleCard and VerseOfTheDay layouts.
3 changes: 1 addition & 2 deletions packages/core/src/styles/bible-reader.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
display: block;

width: 100%;
Comment thread
greptile-apps[bot] marked this conversation as resolved.
/* This helps readability and is a standard max width for text */
max-width: 65ch;
max-width: var(--yv-reader-max-width, 65ch);

--yv-reader-font-size: 20px;
--yv-reader-line-height: 1.625;
Expand Down
48 changes: 46 additions & 2 deletions packages/ui/src/components/bible-card.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ const meta = {
title: 'Components/BibleCard',
component: BibleCard,
parameters: {
layout: 'centered',
layout: 'fullscreen',
},
render: (args) => (
<div className="yv:h-screen yv:w-screen yv:flex yv:justify-center yv:items-center">
<div className="yv:w-full">
<BibleCard {...args} />
</div>
),
Expand Down Expand Up @@ -44,6 +44,50 @@ export const Default: Story = {
versionId: 111,
},
};

export const WideContainer: Story = {
args: {
reference: 'LUK.1.39-45',
versionId: 111,
},
tags: ['integration'],
parameters: {
layout: 'fullscreen',
},
render: (args) => (
<div className="yv:p-8" style={{ width: 900 }}>
<BibleCard {...args} />
</div>
),
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

await waitFor(async () => {
await expect(canvas.getByText(/at that time mary got ready/i)).toBeInTheDocument();
});

const card = canvasElement.querySelector('section[data-yv-sdk][data-yv-theme]');
const contentGroup = canvasElement.querySelector('section[data-yv-sdk][data-yv-theme] > div');
const bibleText = canvasElement.querySelector('[data-slot="yv-bible-renderer"]');

await expect(card).not.toBeNull();
await expect(contentGroup).not.toBeNull();
await expect(bibleText).not.toBeNull();

const cardWidth = card?.getBoundingClientRect().width ?? 0;
const contentGroupRect = contentGroup?.getBoundingClientRect();
const cardRect = card?.getBoundingClientRect();
const leftWhitespace = (contentGroupRect?.left ?? 0) - (cardRect?.left ?? 0);
const rightWhitespace = (cardRect?.right ?? 0) - (contentGroupRect?.right ?? 0);
const bibleTextWidth = bibleText?.getBoundingClientRect().width ?? 0;

await expect(cardWidth).toBeGreaterThan(800);
await expect(contentGroupRect?.width ?? 0).toBeLessThanOrEqual(600);
await expect(bibleTextWidth).toBeLessThanOrEqual(600);
await expect(Math.abs(leftWhitespace - rightWhitespace)).toBeLessThanOrEqual(1);
},
};

export const DarkMode: Story = {
args: {
reference: 'LUK.1.39-45',
Expand Down
20 changes: 20 additions & 0 deletions packages/ui/src/components/bible-card.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,24 @@ describe('BibleCard - Delayed spinner', () => {
0,
);
});

it('should let the card fill its container while centering the content group', () => {
vi.mocked(usePassage).mockReturnValue({
passage: mockPassage,
loading: false,
error: null,
refetch: vi.fn(),
});

const { container } = render(<BibleCard reference="JHN.3.16" versionId={3034} />);
const card = container.querySelector('section');
const contentGroup = container.querySelector('section > div');
const bibleTextView = container.querySelector('[data-slot="yv-bible-renderer"]')?.parentElement;

expect(card).toHaveClass('yv:w-full');
expect(card).not.toHaveClass('yv:max-w-md');
expect(card).toHaveClass('yv:box-border');
expect(contentGroup).toHaveClass('yv:card-content');
expect(bibleTextView).not.toHaveClass('yv:max-w-[600px]');
});
});
78 changes: 40 additions & 38 deletions packages/ui/src/components/bible-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,48 +160,50 @@ export function BibleCard({
<section
data-yv-sdk
data-yv-theme={theme}
className="yv:w-full yv:flex yv:flex-col yv:grow yv:bg-card yv:p-6 yv:max-w-md yv:rounded-2xl"
className="yv:w-full yv:flex yv:flex-col yv:grow yv:bg-card yv:p-6 yv:rounded-2xl yv:box-border"
>
<div className="yv:flex yv:w-full yv:justify-between yv:items-center yv:mb-4">
{passage && !passageError ? (
<div className="yv:grow yv:flex yv:items-center yv:gap-1.5">
<BibleCardHeaderReference passage={passage} version={version} />
{showSpinner ? (
<LoaderIcon className="yv:size-3 yv:animate-spin yv:text-muted-foreground" />
) : null}
</div>
) : passageError ? (
<BibleCardHeaderError />
) : (
<LoaderIcon className="yv:size-3 yv:animate-spin yv:text-muted-foreground" />
)}

{showVersionPicker && !passageError ? (
<BibleCardVersionPicker
versionId={versionNum}
onVersionChange={setVersionNum}
<div className="yv:card-content">
<div className="yv:flex yv:w-full yv:justify-between yv:items-center yv:mb-4">
{passage && !passageError ? (
<div className="yv:grow yv:flex yv:items-center yv:gap-1.5">
<BibleCardHeaderReference passage={passage} version={version} />
{showSpinner ? (
<LoaderIcon className="yv:size-3 yv:animate-spin yv:text-muted-foreground" />
) : null}
</div>
) : passageError ? (
<BibleCardHeaderError />
) : (
<LoaderIcon className="yv:size-3 yv:animate-spin yv:text-muted-foreground" />
)}

{showVersionPicker && !passageError ? (
<BibleCardVersionPicker
versionId={versionNum}
onVersionChange={setVersionNum}
theme={theme}
onVersionPickerPress={onVersionPickerPress}
/>
) : null}
</div>

<AnimatedHeight>
<BibleTextView
theme={theme}
onVersionPickerPress={onVersionPickerPress}
fontSize={16}
fontFamily={SOURCE_SERIF_FONT}
reference={reference}
versionId={versionNum}
passageState={{
passage,
loading: passageLoading,
error: passageError,
}}
/>
) : null}
</div>
</AnimatedHeight>

<AnimatedHeight>
<BibleTextView
theme={theme}
fontSize={16}
fontFamily={SOURCE_SERIF_FONT}
reference={reference}
versionId={versionNum}
passageState={{
passage,
loading: passageLoading,
error: passageError,
}}
/>
</AnimatedHeight>

<BibleCardFooter copyright={!passageError ? version?.copyright : null} />
<BibleCardFooter copyright={!passageError ? version?.copyright : null} />
</div>
</section>
);
}
51 changes: 50 additions & 1 deletion packages/ui/src/components/verse-of-the-day.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ const meta = {
title: 'Components/VerseOfTheDay',
component: VerseOfTheDay,
parameters: {
layout: 'centered',
layout: 'fullscreen',
},
render: (args) => (
<div className="yv:w-full">
<VerseOfTheDay {...args} />
</div>
),
tags: ['autodocs'],
argTypes: {
background: {
Expand Down Expand Up @@ -85,6 +90,50 @@ export const Default: Story = {
},
};

export const WideContainer: Story = {
args: {
versionId: 111,
showSunIcon: true,
showBibleAppAttribution: true,
showShareButton: true,
size: 'default',
},
tags: ['integration'],
parameters: {
layout: 'fullscreen',
},
render: (args) => (
<div className="yv:p-8" style={{ width: 900 }}>
<VerseOfTheDay {...args} />
</div>
),
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

await expect(
await canvas.findByText(/for I am about to do something new/i),
).toBeInTheDocument();

const card = canvasElement.querySelector('section[data-yv-sdk][data-yv-theme]');
const contentGroup = canvasElement.querySelector('section[data-yv-sdk][data-yv-theme] > div');
const bibleText = canvasElement.querySelector('[data-slot="yv-bible-renderer"]');

await expect(card).not.toBeNull();
await expect(contentGroup).not.toBeNull();
await expect(bibleText).not.toBeNull();

const cardRect = card?.getBoundingClientRect();
const contentGroupRect = contentGroup?.getBoundingClientRect();
const leftWhitespace = (contentGroupRect?.left ?? 0) - (cardRect?.left ?? 0);
const rightWhitespace = (cardRect?.right ?? 0) - (contentGroupRect?.right ?? 0);

await expect(cardRect?.width ?? 0).toBeGreaterThan(800);
await expect(contentGroupRect?.width ?? 0).toBeLessThanOrEqual(600);
await expect(bibleText?.getBoundingClientRect().width ?? 0).toBeLessThanOrEqual(600);
await expect(Math.abs(leftWhitespace - rightWhitespace)).toBeLessThanOrEqual(1);
},
};

export const Large: Story = {
args: {
size: 'lg',
Expand Down
11 changes: 11 additions & 0 deletions packages/ui/src/components/verse-of-the-day.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,15 @@ describe('VerseOfTheDay i18n integration', () => {
render(<VerseOfTheDay />);
expect(screen.getByText(en.verseOfTheDay)).toBeInTheDocument();
});

it('lets the card fill its container while centering the content group', () => {
const { container } = render(<VerseOfTheDay />);
const card = container.querySelector('section');
const contentGroup = container.querySelector('section > div');

expect(card).toHaveClass('yv:w-full');
expect(card).not.toHaveClass('yv:max-w-md');
expect(card).toHaveClass('yv:box-border');
expect(contentGroup).toHaveClass('yv:card-content');
});
});
Loading
Loading