diff --git a/.changeset/pretty-bibles-sit.md b/.changeset/pretty-bibles-sit.md new file mode 100644 index 00000000..0fec41c6 --- /dev/null +++ b/.changeset/pretty-bibles-sit.md @@ -0,0 +1,5 @@ +--- +"@youversion/platform-react-ui": minor +--- + +Center card content within full-width BibleCard and VerseOfTheDay layouts. diff --git a/packages/core/src/styles/bible-reader.css b/packages/core/src/styles/bible-reader.css index 870a662d..cc0c289b 100644 --- a/packages/core/src/styles/bible-reader.css +++ b/packages/core/src/styles/bible-reader.css @@ -5,8 +5,7 @@ display: block; width: 100%; - /* 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; diff --git a/packages/ui/src/components/bible-card.stories.tsx b/packages/ui/src/components/bible-card.stories.tsx index cef2605e..5e5ea9b0 100644 --- a/packages/ui/src/components/bible-card.stories.tsx +++ b/packages/ui/src/components/bible-card.stories.tsx @@ -7,10 +7,10 @@ const meta = { title: 'Components/BibleCard', component: BibleCard, parameters: { - layout: 'centered', + layout: 'fullscreen', }, render: (args) => ( -
+
), @@ -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) => ( +
+ +
+ ), + 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', diff --git a/packages/ui/src/components/bible-card.test.tsx b/packages/ui/src/components/bible-card.test.tsx index abc86d42..247cbd32 100644 --- a/packages/ui/src/components/bible-card.test.tsx +++ b/packages/ui/src/components/bible-card.test.tsx @@ -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(); + 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]'); + }); }); diff --git a/packages/ui/src/components/bible-card.tsx b/packages/ui/src/components/bible-card.tsx index 9d5dde6c..58768e40 100644 --- a/packages/ui/src/components/bible-card.tsx +++ b/packages/ui/src/components/bible-card.tsx @@ -160,48 +160,50 @@ export function BibleCard({
-
- {passage && !passageError ? ( -
- - {showSpinner ? ( - - ) : null} -
- ) : passageError ? ( - - ) : ( - - )} - - {showVersionPicker && !passageError ? ( - +
+ {passage && !passageError ? ( +
+ + {showSpinner ? ( + + ) : null} +
+ ) : passageError ? ( + + ) : ( + + )} + + {showVersionPicker && !passageError ? ( + + ) : null} +
+ + + - ) : null} -
+ - - - - - + +
); } diff --git a/packages/ui/src/components/verse-of-the-day.stories.tsx b/packages/ui/src/components/verse-of-the-day.stories.tsx index a7ed075e..2ee55a71 100644 --- a/packages/ui/src/components/verse-of-the-day.stories.tsx +++ b/packages/ui/src/components/verse-of-the-day.stories.tsx @@ -7,8 +7,13 @@ const meta = { title: 'Components/VerseOfTheDay', component: VerseOfTheDay, parameters: { - layout: 'centered', + layout: 'fullscreen', }, + render: (args) => ( +
+ +
+ ), tags: ['autodocs'], argTypes: { background: { @@ -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) => ( +
+ +
+ ), + 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', diff --git a/packages/ui/src/components/verse-of-the-day.test.tsx b/packages/ui/src/components/verse-of-the-day.test.tsx index 8471cbc8..9af55b83 100644 --- a/packages/ui/src/components/verse-of-the-day.test.tsx +++ b/packages/ui/src/components/verse-of-the-day.test.tsx @@ -70,4 +70,15 @@ describe('VerseOfTheDay i18n integration', () => { render(); expect(screen.getByText(en.verseOfTheDay)).toBeInTheDocument(); }); + + it('lets the card fill its container while centering the content group', () => { + const { container } = render(); + 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'); + }); }); diff --git a/packages/ui/src/components/verse-of-the-day.tsx b/packages/ui/src/components/verse-of-the-day.tsx index cdbf8e8e..0744531f 100644 --- a/packages/ui/src/components/verse-of-the-day.tsx +++ b/packages/ui/src/components/verse-of-the-day.tsx @@ -132,92 +132,94 @@ export function VerseOfTheDay({ data-yv-theme={theme} data-size={size} className={ - 'yv:data-[size=lg]:p-8 yv:data-[size=default]:p-4 yv:*:shrink-0 yv:font-sans yv:flex yv:flex-col yv:gap-3 yv:w-full yv:grow yv:max-w-md yv:p-4 yv:rounded-2xl yv:bg-card' + 'yv:data-[size=lg]:p-8 yv:data-[size=default]:p-4 yv:*:shrink-0 yv:font-sans yv:flex yv:flex-col yv:w-full yv:grow yv:p-4 yv:rounded-2xl yv:bg-card yv:box-border' } > -
- {showSunIcon ? ( -
- +
+
+ {showSunIcon ? ( +
+ +
+ ) : null} +
+

+ {t('verseOfTheDay')} +

- ) : null} -
-

- {t('verseOfTheDay')} -

+ {showShareButton ? ( +
+ +
+ ) : null}
- {showShareButton ? ( -
- -
- ) : null} -
+
+ ) : ( +
+ - - {isLoading ? ( + {errorPassage || errorVerseOfTheDay ? null : ( +

+ {referenceText} +

+ )} +
+ )} + + + {showBibleAppAttribution ? (
-
- ) : ( -
- - - {errorPassage || errorVerseOfTheDay ? null : ( -

- {referenceText} -

- )} -
- )} - - - {showBibleAppAttribution ? ( -
- -
- ) : null} + ) : null} +
); } diff --git a/packages/ui/src/styles/global.css b/packages/ui/src/styles/global.css index a3e99a06..f0be6934 100644 --- a/packages/ui/src/styles/global.css +++ b/packages/ui/src/styles/global.css @@ -117,3 +117,9 @@ layer(yv-sdk-fonts); z-index: 9999; } } + +@utility card-content { + width: 100%; + max-width: 600px; + margin-inline: auto; +}