-
-
Notifications
You must be signed in to change notification settings - Fork 1k
feat: add dismissible close button to conference banner #4537
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
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,13 @@ interface IAnnouncementHeroProps { | |
| */ | ||
| export default function AnnouncementHero({ className = '', small = false }: IAnnouncementHeroProps) { | ||
| const [activeIndex, setActiveIndex] = useState(0); | ||
| const [isBannerVisible, setIsBannerVisible] = useState(true); | ||
|
|
||
| // Load banner visibility from localStorage | ||
| useEffect(() => { | ||
| const hidden = localStorage.getItem('bannerClosed'); | ||
| if (hidden === 'true') setIsBannerVisible(false); | ||
| }, []); | ||
|
|
||
| const visibleBanners = useMemo(() => banners.filter((banner) => shouldShowBanner(banner.cfpDeadline)), [banners]); | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| const numberOfVisibleBanners = visibleBanners.length; | ||
|
|
@@ -36,15 +43,17 @@ export default function AnnouncementHero({ className = '', small = false }: IAnn | |
| setActiveIndex(index); | ||
| }; | ||
|
|
||
| const handleClose = () => { | ||
| setIsBannerVisible(false); | ||
| localStorage.setItem('bannerClosed', 'true'); | ||
| }; | ||
|
Comment on lines
57
to
74
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider banner-specific dismissal instead of global dismissal. The current implementation dismisses ALL banners permanently when the close button is clicked, even if the user only intended to dismiss the currently visible banner. Once closed, the banner(s) remain hidden indefinitely until localStorage is manually cleared, which prevents users from seeing new conference announcements. Consider implementing one of these approaches:
Example implementation for banner-specific dismissal: const handleClose = () => {
const currentBanner = visibleBanners[activeIndex];
const dismissedBanners = JSON.parse(localStorage.getItem('dismissedBanners') || '[]');
dismissedBanners.push(currentBanner.eventName);
localStorage.setItem('dismissedBanners', JSON.stringify(dismissedBanners));
// Filter out dismissed banners
const remainingBanners = visibleBanners.filter(
b => !dismissedBanners.includes(b.eventName)
);
if (remainingBanners.length === 0) {
setIsBannerVisible(false);
} else {
// Move to next banner or wrap around
setActiveIndex(prev => prev % remainingBanners.length);
}
};Then update the initial load effect to filter dismissed banners from 🤖 Prompt for AI Agents |
||
|
|
||
| useEffect(() => { | ||
| const interval = setInterval(() => setActiveIndex((index) => (index + 1) % numberOfVisibleBanners), 10000); | ||
|
|
||
| return () => { | ||
| clearInterval(interval); | ||
| }; | ||
| return () => clearInterval(interval); | ||
| }, [numberOfVisibleBanners]); | ||
|
|
||
| if (numberOfVisibleBanners === 0) { | ||
| if (numberOfVisibleBanners === 0 || !isBannerVisible) { | ||
| return null; | ||
| } | ||
|
|
||
|
|
@@ -60,33 +69,42 @@ export default function AnnouncementHero({ className = '', small = false }: IAnn | |
| <ArrowLeft className='text-white' /> | ||
| </div> | ||
| )} | ||
|
|
||
| <div className='relative flex w-4/5 md:w-5/6 flex-col items-center justify-center gap-2'> | ||
| <div className='relative flex min-h-72 w-full justify-center overflow-hidden lg:h-[17rem] lg:w-[38rem]'> | ||
| {visibleBanners.map((banner, index) => { | ||
| // Only render the active banner | ||
| const isVisible = index === activeIndex; | ||
|
|
||
| if (!isVisible) return null; | ||
| if (index !== activeIndex) return null; | ||
|
|
||
| return ( | ||
| <Banner | ||
| key={index} | ||
| title={banner.title} | ||
| dateLocation={banner.dateLocation} | ||
| cfaText={banner.cfaText} | ||
| eventName={banner.eventName} | ||
| cfpDeadline={banner.cfpDeadline} | ||
| link={banner.link} | ||
| city={banner.city} | ||
| activeBanner={isVisible} | ||
| className={className} | ||
| small={small} | ||
| /> | ||
| <div key={index} className='relative w-full flex justify-center'> | ||
| {/* Close Button inside the card */} | ||
| <button | ||
| onClick={handleClose} | ||
| aria-label='Close announcement banner' | ||
| className='absolute top-[1.7rem] right-4 z-20 flex h-6 w-6 items-center justify-center rounded border border-gray-400 bg-white text-gray-600 hover:bg-gray-100 hover:text-gray-800' | ||
| > | ||
| × | ||
| </button> | ||
|
|
||
| <Banner | ||
| title={banner.title} | ||
| dateLocation={banner.dateLocation} | ||
| cfaText={banner.cfaText} | ||
| eventName={banner.eventName} | ||
| cfpDeadline={banner.cfpDeadline} | ||
| link={banner.link} | ||
| city={banner.city} | ||
| activeBanner={index === activeIndex} | ||
| className={className} | ||
| small={small} | ||
| /> | ||
| </div> | ||
| ); | ||
| })} | ||
| </div> | ||
|
|
||
| <div className='m-auto flex justify-center'> | ||
| {visibleBanners.map((banner, index) => ( | ||
| {visibleBanners.map((_, index) => ( | ||
| <div | ||
| key={index} | ||
| className={`mx-1 size-2 cursor-pointer rounded-full ${ | ||
|
|
@@ -97,6 +115,7 @@ export default function AnnouncementHero({ className = '', small = false }: IAnn | |
| ))} | ||
| </div> | ||
| </div> | ||
|
|
||
| {numberOfVisibleBanners > 1 && ( | ||
| <div | ||
| className={`absolute right-0 top-1/2 z-10 mb-2 size-8 -translate-y-1/2 cursor-pointer | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| /// <reference types="next" /> | ||
| /// <reference types="next/image-types/global" /> | ||
| /// <reference path="./.next/types/routes.d.ts" /> | ||
|
|
||
| // NOTE: This file should not be edited | ||
| // see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainVerify if this auto-generated file should be version controlled. This file is auto-generated by Next.js and typically should not be manually edited or committed to version control (usually listed in Run this script to check if 🏁 Script executed: #!/bin/bash
# Check if next-env.d.ts should be in .gitignore
grep -n "next-env.d.ts" .gitignore || echo "next-env.d.ts not found in .gitignore"Length of output: 37 🏁 Script executed: #!/bin/bash
# Check if next-env.d.ts exists and is tracked
echo "=== Checking if next-env.d.ts exists ==="
ls -la next-env.d.ts 2>/dev/null || echo "File does not exist"
echo ""
echo "=== Checking git status of next-env.d.ts ==="
git ls-files --cached next-env.d.ts 2>/dev/null && echo "File is tracked in git" || echo "File is not tracked"
echo ""
echo "=== Checking .gitignore content for auto-generated patterns ==="
cat .gitignore | head -50Length of output: 234 🏁 Script executed: #!/bin/bash
# Check git diff for changes to next-env.d.ts
echo "=== Git diff for next-env.d.ts ==="
git diff HEAD -- next-env.d.ts 2>/dev/null | head -50 || echo "No diff found"
echo ""
echo "=== Check if file is added (untracked) ==="
git status --short 2>/dev/null | grep -i "next-env" || echo "No untracked next-env files"
echo ""
echo "=== Check if this is a Next.js project ==="
test -f package.json && echo "package.json exists" || echo "No package.json"
test -f next.config.js && echo "next.config.js exists" || echo "No next.config.js"
test -f tsconfig.json && echo "tsconfig.json exists" || echo "No tsconfig.json"
echo ""
echo "=== List TypeScript declaration files ==="
find . -maxdepth 2 -name "*.d.ts" 2>/dev/null | head -10Length of output: 268 Add This auto-generated file should not be committed to version control. Add 🤖 Prompt for AI Agents |
||
Uh oh!
There was an error while loading. Please reload this page.