Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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: 6 additions & 2 deletions packages/shared/src/components/Feed.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@
grid-template-columns: 100%;
}
.container {
@screen laptopL {
max-width: 100%;

@screen desktopL {
max-width: calc(20rem * var(--num-cards) + var(--feed-gap) * (var(--num-cards) - 1));
}
}
.cards {
@screen mobileL {
max-width: 100%;

@screen desktopL {
max-width: calc(20rem * var(--num-cards) + var(--feed-gap) * (var(--num-cards) - 1));
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/shared/src/components/Feed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,9 @@ export default function Feed<T>({
const currentSettings = useContext(FeedContext);
const { user } = useContext(AuthContext);
const { isFallback, query: routerQuery } = useRouter();
const { openNewTab, spaciness, loadedSettings } = useContext(SettingsContext);
const { openNewTab, loadedSettings } = useContext(SettingsContext);
const { isListMode } = useFeedLayout();
const numCards = currentSettings.numCards[spaciness ?? 'eco'];
const numCards = currentSettings.numCards.eco;
const isSquadFeed = feedName === OtherFeedPage.Squad;
const { shouldUseListFeedLayout } = useFeedLayout();
const trackedFeedFinish = useRef(false);
Expand Down
4 changes: 2 additions & 2 deletions packages/shared/src/components/MainLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,14 +196,14 @@ function MainLayoutComponent({
/>
<main
className={classNames(
'flex flex-col',
'flex flex-col transition-[padding] duration-300 ease-in-out laptop:pt-16',
showSidebar && 'tablet:pl-16 laptop:pl-11',
className,
isAuthReady &&
!isScreenCentered &&
sidebarExpanded &&
'laptop:!pl-60',
isBannerAvailable && 'laptop:pt-8',
isBannerAvailable && 'laptop:pt-24',
)}
>
{isAuthReady && showSidebar && (
Expand Down
14 changes: 8 additions & 6 deletions packages/shared/src/components/feeds/FeedContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ const cardListClass = {
export const getFeedGapPx = {
'gap-2': 8,
'gap-3': 12,
'gap-4': 16,
'gap-5': 20,
'gap-6': 24,
'gap-8': 32,
'gap-12': 48,
'gap-14': 56,
Expand All @@ -87,7 +89,7 @@ export const gapClass = ({
if (isFeedLayoutList) {
return '';
}
return isList ? listGaps[space] ?? 'gap-2' : gridGaps[space] ?? 'gap-8';
return isList ? listGaps[space] ?? 'gap-2' : gridGaps[space] ?? 'gap-4';
};

const cardClass = ({
Expand Down Expand Up @@ -149,15 +151,15 @@ export const FeedContainer = ({
}: FeedContainerProps): ReactElement => {
const currentSettings = useContext(FeedContext);
const { subject } = useToastNotification();
const { spaciness, loadedSettings } = useContext(SettingsContext);
const { loadedSettings } = useContext(SettingsContext);
const { shouldUseListFeedLayout, isListMode } = useFeedLayout();
const isLaptop = useViewSize(ViewSize.Laptop);
const { feedName } = useActiveFeedNameContext();
const { isAnyExplore, isExplorePopular, isExploreLatest } = useFeedName({
feedName,
});
const router = useRouter();
const numCards = currentSettings.numCards[spaciness ?? 'eco'];
const numCards = currentSettings.numCards.eco;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You basically removed this right? (the settings, I think we should clean it up, but I can do it afterwords if you want?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I will remove it, but I think we should wait and see if users do not complain too much, then we can remove it completely. The new layout has better UX

const isList =
(isHorizontal || isListMode) && !shouldUseListFeedLayout
? false
Expand All @@ -167,14 +169,14 @@ export const FeedContainer = ({
gapClass({
isList,
isFeedLayoutList: shouldUseListFeedLayout,
space: spaciness,
space: 'eco',
})
];
const style = {
'--num-cards': isHorizontal && isListMode && numCards >= 2 ? 2 : numCards,
'--feed-gap': `${feedGapPx / 16}rem`,
} as CSSProperties;
const cardContainerStyle = { ...getStyle(isList, spaciness) };
const cardContainerStyle = { ...getStyle(isList, 'eco') };
const isFinder = router.pathname === '/search/posts';
const isSearch = showSearch && !isFinder;

Expand Down Expand Up @@ -322,7 +324,7 @@ export const FeedContainer = ({
gapClass({
isList,
isFeedLayoutList: shouldUseListFeedLayout,
space: spaciness,
space: 'eco',
}),
cardClass({ isList, numberOfCards: numCards, isHorizontal }),
)}
Expand Down
43 changes: 3 additions & 40 deletions packages/shared/src/components/feeds/FeedNav.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import classNames from 'classnames';
import type { ReactElement } from 'react';
import React, { useMemo, useState, useTransition } from 'react';
import React, { useMemo } from 'react';
import { useRouter } from 'next/router';
import { Tab, TabContainer } from '../tabs/TabContainer';
import { useActiveFeedNameContext } from '../../contexts';
import useActiveNav from '../../hooks/useActiveNav';
import { useEventListener, useFeeds, useViewSize, ViewSize } from '../../hooks';
import { useFeeds, useViewSize, ViewSize } from '../../hooks';
import usePersistentContext from '../../hooks/usePersistentContext';
import {
algorithmsList,
Expand All @@ -31,7 +31,6 @@ import { SharedFeedPage } from '../utilities';
import PlusMobileEntryBanner from '../banners/PlusMobileEntryBanner';
import { TargetType } from '../../lib/log';
import usePlusEntry from '../../hooks/usePlusEntry';
import { useAlertsContext } from '../../contexts/AlertContext';

enum FeedNavTab {
ForYou = 'For you',
Expand All @@ -52,17 +51,12 @@ const StickyNavIconWrapper = classed(
'sticky flex h-14 pt-1 -translate-y-16 items-center justify-end bg-gradient-to-r from-transparent via-background-default via-40% to-background-default pr-4',
);

const MIN_SCROLL_BEFORE_HIDING = 60;

function FeedNav(): ReactElement {
const router = useRouter();
const [, startTransition] = useTransition();
const [isHeaderVisible, setIsHeaderVisible] = useState(true);
const { feedName } = useActiveFeedNameContext();
const { sortingEnabled } = useSettingsContext();
const { isSortableFeed } = useFeedName({ feedName });
const { home, bookmarks } = useActiveNav(feedName);
const { alerts } = useAlertsContext();
const isMobile = useViewSize(ViewSize.MobileL);
const [selectedAlgo, setSelectedAlgo] = usePersistentContext(
DEFAULT_ALGORITHM_KEY,
Expand All @@ -82,8 +76,6 @@ function FeedNav(): ReactElement {
isMobile &&
((sortingEnabled && isSortableFeed) || feedName === SharedFeedPage.Custom);

const hasOpportunityAlert = !!alerts.opportunityId;

const urlToTab: Record<string, FeedNavTab> = useMemo(() => {
const customFeeds = sortedFeeds.reduce((acc, { node: feed }) => {
const isEditingFeed =
Expand Down Expand Up @@ -127,45 +119,16 @@ function FeedNav(): ReactElement {
isCustomDefaultFeed,
]);

const previousScrollY = React.useRef(0);

useEventListener(globalThis, 'scroll', () => {
// when scrolled down we should hide the header
// when scrolled up, we should bring it back
const { scrollY } = window;
const shouldHeaderBeVisible = scrollY < previousScrollY.current;

previousScrollY.current = scrollY;

if (shouldHeaderBeVisible === isHeaderVisible) {
return;
}

if (!shouldHeaderBeVisible && scrollY < MIN_SCROLL_BEFORE_HIDING) {
return;
}

startTransition(() => {
setIsHeaderVisible(shouldHeaderBeVisible);
});
});
const shouldRenderNav = home || (isMobile && bookmarks);
if (!shouldRenderNav || router?.pathname?.startsWith('/posts/[id]')) {
return null;
}

const headerTransitionClasses =
isMobile && hasOpportunityAlert
? '-translate-y-[7.5rem] duration-[800ms]'
: '-translate-y-26 duration-[800ms]';

return (
<div
className={classNames(
'sticky top-0 z-header w-full transition-transform tablet:pl-16',
'sticky top-0 z-header w-full bg-background-default tablet:pl-16',
scrollClassName,
isHeaderVisible && 'translate-y-0 duration-200',
!isHeaderVisible && headerTransitionClasses,
)}
>
{isMobile && <MobileFeedActions />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ function MainLayoutHeader({
return (
<header
className={classNames(
'sticky top-0 z-header h-14 flex-row content-center items-center justify-center gap-3 border-b border-border-subtlest-tertiary px-4 py-3 tablet:px-8 laptop:left-0 laptop:h-16 laptop:w-full laptop:px-4',
'fixed top-0 z-header h-14 flex-row content-center items-center justify-center gap-3 border-b border-border-subtlest-tertiary bg-background-default px-4 py-3 tablet:px-8 laptop:left-0 laptop:h-16 laptop:w-full laptop:px-4',
isMobileProfile ? 'hidden laptop:flex' : 'flex',
hasBanner && 'laptop:top-8',
isSearchPage && 'mb-16 laptop:mb-0',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { ComponentProps, PropsWithChildren, ReactElement } from 'react';
import React from 'react';
import classNames from 'classnames';

export const pageMainClassNames = 'tablet:p-4 laptop:px-10 laptop:py-5';
export const pageMainClassNames = 'tablet:p-4 laptop:p-10';

export const PageWrapperLayout = ({
children,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { PropsWithChildren, ReactElement } from 'react';
import React, { useContext } from 'react';
import React from 'react';
import { useRouter } from 'next/router';
import classNames from 'classnames';
import { PageWidgets } from '../../utilities';
Expand All @@ -12,7 +12,6 @@ import { webappUrl } from '../../../lib/constants';
import { SearchResultsTags } from './SearchResultsTags';
import { SearchResultsSources } from './SearchResultsSources';
import { useSearchProviderSuggestions } from '../../../hooks/search';
import SettingsContext from '../../../contexts/SettingsContext';
import { gapClass } from '../../feeds/FeedContainer';
import { useFeedLayout } from '../../../hooks';
import { SearchResultsUsers } from './SearchResultsUsers';
Expand All @@ -26,7 +25,6 @@ export const SearchResultsLayout = (
): ReactElement => {
const { children } = props;
const { isListMode } = useFeedLayout();
const { spaciness } = useContext(SettingsContext);
const { isSearchPageLaptop } = useSearchResultsLayout();

const {
Expand Down Expand Up @@ -103,7 +101,7 @@ export const SearchResultsLayout = (
gapClass({
isList: true,
isFeedLayoutList: false,
space: spaciness,
space: 'eco',
}),
isListMode
? `flex flex-col`
Expand Down
92 changes: 68 additions & 24 deletions packages/shared/src/components/sidebar/Section.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import classNames from 'classnames';
import type { ReactElement } from 'react';
import React, { useRef } from 'react';
import React, { useRef, useCallback } from 'react';
import type { ItemInnerProps, SidebarMenuItem } from './common';
import { NavHeader, NavSection } from './common';
import { SidebarItem } from './SidebarItem';
import { Button, ButtonSize, ButtonVariant } from '../buttons/Button';
import { ArrowIcon } from '../icons';
import { ArrowIcon, PlusIcon } from '../icons';
import type { SettingsFlags } from '../../graphql/settings';
import { useSettingsContext } from '../../contexts/SettingsContext';
import { isNullOrUndefined } from '../../lib/func';
import useSidebarRendered from '../../hooks/useSidebarRendered';
import Link from '../utilities/Link';

export interface SectionCommonProps
extends Pick<ItemInnerProps, 'shouldShowLabel'> {
Expand All @@ -24,6 +24,8 @@ interface SectionProps extends SectionCommonProps {
items: SidebarMenuItem[];
isItemsButton: boolean;
isAlwaysOpenOnMobile?: boolean;
onAdd?: () => void;
addHref?: string;
}

export function Section({
Expand All @@ -36,43 +38,84 @@ export function Section({
className,
flag,
isAlwaysOpenOnMobile,
onAdd,
addHref,
}: SectionProps): ReactElement {
const { flags, updateFlag } = useSettingsContext();
const { sidebarRendered } = useSidebarRendered();
const shouldAlwaysBeVisible = isAlwaysOpenOnMobile && !sidebarRendered;
const isVisible = useRef(
isNullOrUndefined(flags?.[flag]) ? true : flags[flag],
);
const toggleFlag = () => {
const toggleFlag = useCallback(() => {
updateFlag(flag, !isVisible.current);
isVisible.current = !isVisible.current;
};
}, [updateFlag, flag]);

return (
<NavSection className={className}>
<NavSection className={classNames('mt-1', className)}>
{title && (
<NavHeader
className={classNames(
'hidden justify-between laptop:flex',
sidebarExpanded ? 'px-3 opacity-100' : 'px-0 opacity-0',
)}
>
{title}
<Button
variant={ButtonVariant.Tertiary}
onClick={toggleFlag}
size={ButtonSize.XSmall}
aria-label={`Toggle ${title}`}
icon={
<NavHeader className="hidden laptop:flex">
<div
className={classNames(
'group/section flex w-full items-center justify-between px-2 py-1.5 transition-opacity duration-300',
sidebarExpanded ? 'opacity-100' : 'pointer-events-none opacity-0',
)}
>
<button
type="button"
onClick={toggleFlag}
aria-label={`Toggle ${title}`}
aria-expanded={!!isVisible.current}
className="flex items-center gap-1 rounded-6 transition-colors hover:text-text-primary"
>
<span
className={classNames(
'text-text-quaternary typo-callout',
!sidebarExpanded && 'opacity-0',
)}
>
{title}
</span>
<ArrowIcon
className={isVisible.current ? 'rotate-360' : 'rotate-180'}
className={classNames(
'h-2.5 w-2.5 text-text-quaternary transition-transform duration-200',
isVisible.current ? 'rotate-180' : 'rotate-90',
)}
/>
}
/>
</button>
{addHref && (
<Link href={addHref}>
<a
aria-label={`Add to ${title}`}
className="flex h-6 w-6 items-center justify-center rounded-6 text-text-tertiary transition-all hover:bg-surface-hover hover:text-text-primary"
>
<PlusIcon className="h-4 w-4" />
</a>
</Link>
)}
{!addHref && onAdd && (
<button
type="button"
onClick={onAdd}
aria-label={`Add to ${title}`}
className="flex h-6 w-6 items-center justify-center rounded-6 text-text-tertiary transition-all hover:bg-surface-hover hover:text-text-primary"
>
<PlusIcon className="h-4 w-4" />
</button>
)}
</div>
</NavHeader>
)}
{(isVisible.current || shouldAlwaysBeVisible) &&
items.map((item) => (
<div
className={classNames(
'flex flex-col overflow-hidden transition-all duration-300',
isVisible.current || shouldAlwaysBeVisible
? 'max-h-[2000px] opacity-100' // Using large max-height for CSS transition animation
: 'max-h-0 opacity-0',
)}
>
{items.map((item) => (
<SidebarItem
key={`${item.title}-${item.path}`}
item={item}
Expand All @@ -81,6 +124,7 @@ export function Section({
shouldShowLabel={shouldShowLabel}
/>
))}
</div>
</NavSection>
);
}
Loading