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: Dynamic web stories from backend #892

Merged
merged 50 commits into from
Dec 28, 2024
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
d45a0d2
Add callbacks to call for fetching data from backend.
amovar18 Dec 12, 2024
db4ed0f
Merge branch 'release/v0.13.0' of github.com:GoogleChromeLabs/ps-anal…
amovar18 Dec 13, 2024
8b74cc0
Fix redundant calls to category and authors.
amovar18 Dec 16, 2024
e0043aa
Add callbacks for tags.
amovar18 Dec 16, 2024
a08ad75
Add sorting order for stories.
amovar18 Dec 16, 2024
1530082
Early exit from amp player main.js
amovar18 Dec 17, 2024
ca71fec
Add loader for iframe contents to load.
amovar18 Dec 17, 2024
28257ed
Allow changes E2E run against develop main and release branches.
amovar18 Dec 17, 2024
4a54ae3
Revert change.
amovar18 Dec 17, 2024
b1e8ff0
Convert stories to WebStories.
amovar18 Dec 17, 2024
9320074
Change references of story to webStory.
amovar18 Dec 17, 2024
049deef
Change comment of header from 2023 to 2024
amovar18 Dec 17, 2024
2ac98e8
Remove unused tests.
amovar18 Dec 17, 2024
07a0ed1
Decrease min width for sort by
mayan-000 Dec 17, 2024
4d082b4
Fix erros and colors.
amovar18 Dec 18, 2024
4983751
Merge branch 'feat/dynamic-web-stories' of github.com:GoogleChromeLab…
amovar18 Dec 18, 2024
d9ce9d4
use URLSearchParams instead of creating a string.
amovar18 Dec 18, 2024
fc989af
Add infinite scroll to the stories loader.
amovar18 Dec 18, 2024
8117b97
Change per page fetch to 12.
amovar18 Dec 18, 2024
b0d89eb
Fix sort by width.
amovar18 Dec 20, 2024
8f2d2cb
Modify init to add stories programatically
amovar18 Dec 20, 2024
48efe0c
Fix bugs of filter not working.
amovar18 Dec 20, 2024
4c6944c
Change condition to reduce the number of api calls.
amovar18 Dec 23, 2024
a1a8b7e
Fix errors on extension page.
amovar18 Dec 23, 2024
9023085
Merge branch 'release/v0.13.0' of github.com:GoogleChromeLabs/ps-anal…
amovar18 Dec 23, 2024
55fb8d0
Add appropriate names to listeners.
amovar18 Dec 23, 2024
a65f8f4
Add no-sandbox to tests.
amovar18 Dec 23, 2024
893b701
Fix failing test and add some fixes.
amovar18 Dec 23, 2024
b9f4e16
Add arrow to show scroll more.
amovar18 Dec 24, 2024
233dad3
Change icon for dark mode.
amovar18 Dec 24, 2024
746ef2b
Add event listeners to the down and to button.
amovar18 Dec 25, 2024
954c448
Reduce placement from right for arrow.
amovar18 Dec 25, 2024
d617441
Fix spelling mistake.
amovar18 Dec 25, 2024
b2068b2
Fix wrong story display bug
amovar18 Dec 25, 2024
08a5204
Fix feedbacks:
amovar18 Dec 26, 2024
81e4632
Move iframe contents to a new component..
amovar18 Dec 26, 2024
deeb0d2
Hide up arrow when user reaches the top.
amovar18 Dec 26, 2024
7b96a06
Add smooth to scrollIntoView.
amovar18 Dec 26, 2024
336d448
Remove cursor css.
amovar18 Dec 26, 2024
f1d9588
Fix bug of switching tabs and story disappearence.
amovar18 Dec 26, 2024
c110120
Redefine logic of scrolling.
amovar18 Dec 27, 2024
0d51798
Fix searchValue using old page number.
amovar18 Dec 27, 2024
31e193a
Move amp-player-main to custom scripts
amovar18 Dec 27, 2024
8efc77d
Move api fetching logic to separate functions.
amovar18 Dec 27, 2024
03c388d
Change API path.
amovar18 Dec 27, 2024
e2e34ad
Fix bugs in fetcher.
amovar18 Dec 27, 2024
b14f1e2
Move BASE_API_URL to constants file.
amovar18 Dec 27, 2024
887f548
Use math.ceil for calculation.
amovar18 Dec 27, 2024
3b4d7f9
Use document insetad of window.document.
amovar18 Dec 27, 2024
bd2f9b3
Move utilities to utils folder.
amovar18 Dec 27, 2024
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
232 changes: 193 additions & 39 deletions assets/amp/amp-player-main.js
amovar18 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ let maxScroll;
let scaleVal = 1;
let scalingDown = false;
let deltaY = 0;
let previousStories = [];
let doesHaveMorePages = false;
amovar18 marked this conversation as resolved.
Show resolved Hide resolved

function setPlayer(playerEl) {
player = playerEl;
Expand All @@ -47,33 +49,39 @@ function setCardMargin(margin) {
* Initializes arrows for horizontal scrolling on desktop.
*/
function initializeArrows() {
const scrollContainer = document.querySelector('.carousel-cards-container');
const containerPadding =
parseFloat(
getComputedStyle(scrollContainer.firstElementChild).paddingLeft
) +
parseFloat(
getComputedStyle(scrollContainer.firstElementChild).paddingRight
);

maxScroll =
scrollContainer.offsetWidth -
containerPadding +
cardMargin -
cards.length * cardWidth;

if (maxScroll < 0) {
document.querySelector('.carousel-container').classList.add('overflow-right');
try {
const scrollContainer = document.querySelector('.carousel-cards-container');
const containerPadding =
parseFloat(
getComputedStyle(scrollContainer.firstElementChild).paddingLeft
) +
parseFloat(
getComputedStyle(scrollContainer.firstElementChild).paddingRight
);

maxScroll =
scrollContainer.offsetWidth -
containerPadding +
cardMargin -
cards.length * cardWidth;

if (maxScroll < 0) {
document
.querySelector('.carousel-container')
.classList.add('overflow-right');
}
} catch (error) {
//Fail silently
}
}

/**
* Closes the lightbox and resets the player and UI.
*/
function closePlayer() {
const data = { storyOpened: false }
const event = new CustomEvent('webStoriesLightBoxEvent', { detail: data })
window.parent.document.dispatchEvent(event)
const data = { storyOpened: false };
const event = new CustomEvent('webStoriesLightBoxEvent', { detail: data });
window.parent.document.dispatchEvent(event);
player.pause();
document.body.classList.remove('lightbox-open');
lightboxEl.classList.add('closed');
Expand Down Expand Up @@ -107,26 +115,31 @@ function resetStyles() {
* Initializes card click events and sets up their dimensions.
*/
function initializeCards() {
setCards(document.querySelectorAll('.entry-point-card-container'));
setCardMargin(parseFloat(getComputedStyle(cards[0]).marginRight));
setCardWidth(cardMargin + cards[0].offsetWidth);

const stories = player.getStories();

cards.forEach((card, idx) => {
card.addEventListener('click', () => {
player.show(stories[idx].href, null, { animate: false });
const data = { storyOpened: true }
const event = new CustomEvent('webStoriesLightBoxEvent', { detail: data })
window.parent.document.dispatchEvent(event)

document.body.classList.add('lightbox-open');
lightboxEl.classList.remove('closed');
card.classList.add('hidden');
resetStyles();
player.play();
try {
setCards(document.querySelectorAll('.entry-point-card-container'));
setCardMargin(parseFloat(getComputedStyle(cards[0]).marginRight));
setCardWidth(cardMargin + cards[0].offsetWidth);

cards.forEach((card, idx) => {
card.addEventListener('click', () => {
player.show(card.dataset.storyUrl, null, { animate: false });
const data = { storyOpened: true };
const event = new CustomEvent('webStoriesLightBoxEvent', {
detail: data,
});
window.parent.document.dispatchEvent(event);

document.body.classList.add('lightbox-open');
lightboxEl.classList.remove('closed');
card.classList.add('hidden');
resetStyles();
player.play();
});
});
});
} catch (error) {
//Fail silently
console.log(error);
}
}

/**
Expand All @@ -139,6 +152,9 @@ function initializeCarousel() {
initializeCards();
initializeArrows();

const event = new CustomEvent('iframeLoaded');
window.parent.document.dispatchEvent(event);

player.addEventListener('amp-story-player-close', closePlayer);
}

Expand All @@ -148,6 +164,7 @@ function initializeCarousel() {
function init() {
const playerEl = document.body.querySelector('amp-story-player');
setPlayer(playerEl);
previousStories = [];

if (player.isReady) {
initializeCarousel();
Expand All @@ -170,5 +187,142 @@ function easeOutQuad(t) {
return --t * t * t + 1;
}

const sendEventToParent = () => {
const event = new CustomEvent('loadMoreData');
window.parent.document.dispatchEvent(event);
};

function scrollListener() {
if (
window.scrollY + window.innerHeight >=
document.documentElement.scrollHeight
) {
sendEventToParent();
}

if(window.scrollY > 0 && !doesHaveMorePages){
document.getElementById('show-more-indicator').style.display = 'block';
document.getElementById('show-more-indicator').style.rotate = '180deg';
document.getElementById('show-more-indicator').onclick = () => {
document.body.scrollIntoView({behavior: 'smooth'});
};
}

if(window.scrollY === 0 && !doesHaveMorePages){
document.getElementById('show-more-indicator').style.display = 'none';
}
}

const getCardHTML = ({
heroImage,
publisherLogo,
publisherName,
storyTitle,
storyUrl,
}) => {
return `
<div class="entry-point-card-container" data-story-url="${storyUrl}">
<div class="background-cards">
<div class="background-card-1"></div>
<div class="background-card-2"></div>
</div>
<img src="${heroImage}" class="entry-point-card-img" alt="A cat">
<div class="author-container">
<div class="logo-container">
<div class="logo-ring"></div>
<img class="entry-point-card-logo" src="${publisherLogo}" alt="Publisher logo">
</div>
<span class="entry-point-card-subtitle"> By ${publisherName} </span>
</div>
<div class="card-headline-container">
<span class="entry-point-card-headline"> ${storyTitle} </span>
</div>
</div>
`;
};

const messageListener = ({
data: { story, doesHaveMorePages: _doesHaveMorePages },
}) => {
try {
const _cards = story.map(getCardHTML).join('');
const storyAnchors = story.map(({ storyUrl }) => ({ href: storyUrl }));

if (JSON.stringify(story) === JSON.stringify(previousStories)) {
return;
}

document.getElementById('entry-points').innerHTML = _cards;
const scrollToNext = previousStories.length;
previousStories = story;
player.add(storyAnchors);

initializeCards();
initializeArrows();
doesHaveMorePages = _doesHaveMorePages;

cards[scrollToNext].scrollIntoView({behavior: 'smooth'});

const distanceToRight = calculateDistanceBetweenLastItemAndBox();
document.getElementById('show-more-indicator').style.left = `calc(100% - ${
distanceToRight / 2
}px)`;

if(!doesHaveMorePages){
if(window.scrollY > 0){
document.getElementById('show-more-indicator').style.rotate = '180deg';
}else{
document.getElementById('show-more-indicator').style.display = 'none';
}
}else{
document.getElementById('show-more-indicator').classList.add('bounce');
document.getElementById('show-more-indicator').onclick = () => {
sendEventToParent();
};
setTimeout(() => {
document.getElementById('show-more-indicator').classList.remove('bounce');
}, 2000);
}
} catch (error) {
//Fail silently
}
};

const calculateDistanceBetweenLastItemAndBox = () => {
const flexContainer = document.querySelector('.entry-points');
const flexItems = Array.from(flexContainer.children);

let lastItemFirstRow = null;

let firstRowBottom = 0;

for (let i = 0; i < flexItems.length; i++) {
const itemRect = flexItems[i].getBoundingClientRect();

if (i === 0) {
firstRowBottom = itemRect.bottom;
}

if (itemRect.bottom <= firstRowBottom) {
lastItemFirstRow = flexItems[i];
} else {
break;
}
}

// Get the position of the container
const containerRect = flexContainer.getBoundingClientRect();

// Calculate the distance from the rightmost part of the container to the last item in the first row
if (lastItemFirstRow) {
const lastItemRect = lastItemFirstRow.getBoundingClientRect();
const distanceToRight = containerRect.right - lastItemRect.right;
return distanceToRight + 36;
}
return null;
};

// Initialize on window load.
window.addEventListener('load', init);
window.addEventListener('scroll', scrollListener);
window.addEventListener('message', messageListener);
8 changes: 6 additions & 2 deletions packages/design-system/src/components/progressBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ import React from 'react';

interface ProgressBarProps {
additionalStyles?: string;
barAdditionalStyles?: string;
}
const ProgressBar = ({ additionalStyles = '' }: ProgressBarProps) => {
const ProgressBar = ({
additionalStyles = '',
barAdditionalStyles = 'bg-gainsboro dark:bg-neutral-600',
}: ProgressBarProps) => {
return (
<div
data-testid="progress-bar"
className={`${additionalStyles} flex justify-center flex-col gap-2 relative overflow-hidden`}
>
<div className="mb-6 h-1 w-full bg-gainsboro dark:bg-neutral-600 overflow-hidden">
<div className={`${barAdditionalStyles} mb-6 h-1 w-full overflow-hidden`}>
<div className="h-1 w-1/2 bg-royal-blue absolute animate-horizontal-spinner"></div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,38 @@ import { noop } from '@google-psat/common';
/**
* Internal dependencies.
*/
import { getStoryMarkup } from './createStoryIframe';
import { STORY_JSON } from './story';
import { useStories } from '../../stateProviders';
import { useWebStories } from '../../stateProviders';
import { MainContentContainer } from './mainContentContainer';

interface WebStoriesProps {
storyOpened: boolean;
}

const WebStories = ({ storyOpened }: WebStoriesProps) => {
const storyMarkup = getStoryMarkup(STORY_JSON);

const {
allStoryJSON,
searchValue,
setSearchValue,
showFilterSidebar,
setShowFilterSidebar,
setSortValue,
sortValue,
selectedFilters,
toggleFilterSelection,
resetFilters,
selectedFilterValues,
filters,
} = useStories(({ state, actions }) => ({
setSearchValue,
setShowFilterSidebar,
setSortValue,
toggleFilterSelection,
resetFilters,
} = useWebStories(({ state, actions }) => ({
allStoryJSON: state.allStoryJSON,
searchValue: state.searchValue,
filters: state.filters,
sortValue: state.sortValue,
selectedFilterValues: state.selectedFilterValues,
setSearchValue: actions.setSearchValue,
showFilterSidebar: state.showFilterSidebar,
selectedFilters: state.selectedFilters,
setSearchValue: actions.setSearchValue,
setShowFilterSidebar: actions.setShowFilterSidebar,
setSortValue: actions.setSortValue,
selectedFilters: state.selectedFilters,
toggleFilterSelection: actions.toggleFilterSelection,
resetFilters: actions.resetFilters,
}));
Expand All @@ -73,10 +72,10 @@ const WebStories = ({ storyOpened }: WebStoriesProps) => {
hideFiltering={false}
disableFiltering={false}
hideSearch={false}
count={0} // TODO: Add count
count={allStoryJSON.length}
>
<div className="flex justify-between items-center min-w-[125px] text-raisin-black dark:text-bright-gray">
<p>Sort by:</p>
<div className="flex justify-between items-center min-w-[100px] text-raisin-black dark:text-bright-gray">
<p className="min-w-fit">Sort by:</p>
<select
value={sortValue}
onChange={(e) =>
Expand All @@ -91,8 +90,8 @@ const WebStories = ({ storyOpened }: WebStoriesProps) => {
backgroundPositionY: '4px',
}}
>
<option value="Latest">Latest</option>
<option value="Oldest">Oldest</option>
<option value="latest">Latest</option>
<option value="oldest">Oldest</option>
</select>
</div>
</TopBar>
Expand Down Expand Up @@ -125,15 +124,9 @@ const WebStories = ({ storyOpened }: WebStoriesProps) => {
data-testid="web-stories-content"
className="h-full flex-1 text-raisin-black dark:text-bright-gray"
>
<iframe
srcDoc={storyMarkup}
style={{
width: '100%',
height: '100%',
border: 'none',
overflow: 'hidden',
}}
/>
<div className="h-full w-full flex">
<MainContentContainer />
</div>
</div>
</div>
</div>
Expand Down
Loading
Loading