Skip to content

Redesign footer with elegant dark theme#731

Merged
4tal merged 2 commits into4tals:mainfrom
4tala:design/elegant-footer
Feb 8, 2026
Merged

Redesign footer with elegant dark theme#731
4tal merged 2 commits into4tals:mainfrom
4tala:design/elegant-footer

Conversation

@4tala
Copy link
Copy Markdown
Contributor

@4tala 4tala commented Feb 8, 2026

Summary

Modernizes the footer with a sleek, elegant dark design that feels more polished and professional.

Before → After

Before: White background with gray text, standard blue button, basic hover effects

After:

  • 🌙 Dark gradient background (#1a1a2e#16213e)
  • ✨ Subtle backdrop blur effect
  • 🎨 White/translucent social icons with smooth hover animations
  • 💫 Minimal < Contribute /> button with border-only style
  • 📱 Clean responsive layout for mobile

Changes

Footer.tsx

  • Dark gradient background replacing white
  • Simplified component structure (removed verbose style objects)
  • Inverted social icons to white with opacity for elegance
  • Added backdrop blur for modern glass effect
  • Cleaner hover animations (translateY + opacity changes)

HelpUsButton.tsx

  • Changed from solid blue to transparent with border
  • Updated text to < Contribute /> (more dev-friendly)
  • Pill-shaped border radius
  • Monospace font for code aesthetic

Visual Preview

The footer now has a modern dark theme that:

  • Contrasts nicely with the main content
  • Feels more premium and polished
  • Has subtle, satisfying micro-interactions
  • Matches current design trends

- Replace white background with sleek dark gradient
- Simplify layout and improve spacing
- Add subtle hover animations
- Update social icons to white with opacity
- Redesign contribute button with minimal border style
- Improve mobile responsiveness
- Add backdrop blur effect for modern look
@netlify
Copy link
Copy Markdown

netlify bot commented Feb 8, 2026

Deploy Preview for linksforisrael ready!

Name Link
🔨 Latest commit 3a62896
🔍 Latest deploy log https://app.netlify.com/projects/linksforisrael/deploys/6988862697cc8200084d0090
😎 Deploy Preview https://deploy-preview-731--linksforisrael.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Redesign footer with elegant dark theme and minimal styling

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Redesign footer with elegant dark gradient theme
  - Replace white background with dark gradient (#1a1a2e to #16213e)
  - Add backdrop blur effect for modern glass morphism
  - Invert social icons to white with opacity
• Simplify component structure and remove verbose styles
  - Consolidate inline styles into component props
  - Remove separate FOOTER_STYLES object
  - Eliminate Tooltip components for cleaner UI
• Update contribute button with minimal border style
  - Change from solid blue to transparent with border
  - Update text to "< Contribute />" for dev aesthetic
  - Use monospace font with pill-shaped border radius
• Improve responsive layout for mobile and desktop
  - Unified single return statement with conditional rendering
  - Better spacing and alignment across breakpoints
Diagram
flowchart LR
  A["White Background<br/>Gray Text<br/>Solid Blue Button"] -->|Dark Theme| B["Dark Gradient BG<br/>White Icons<br/>Border Button"]
  B -->|Backdrop Blur| C["Glass Effect<br/>Modern Look"]
  B -->|Simplified Styles| D["Inline Props<br/>No Tooltips<br/>Cleaner Code"]
Loading

Grey Divider

File Changes

1. app/components/Footer/Footer.tsx ✨ Enhancement +123/-149

Dark gradient background with simplified styling

• Replace white background with dark gradient (135deg, #1a1a2e to #16213e)
• Add backdrop blur effect and updated border styling with whiteAlpha colors
• Remove FOOTER_STYLES object and consolidate styles into component props
• Remove Tooltip components wrapping social icons and reverse image link
• Invert social icons to white using filter brightness and opacity
• Simplify mobile/desktop layout into single return with conditional rendering
• Update spacing, typography, and hover animations for dark theme

app/components/Footer/Footer.tsx


2. app/components/Footer/HelpUsButton.tsx ✨ Enhancement +18/-16

Minimal border button with monospace contribute text

• Change button style from solid blue background to transparent with border
• Update text from "< כניסה למפתחים >" to "< Contribute />"
• Switch to monospace font (JetBrains Mono, Fira Code, Consolas)
• Change border radius from 8px to full (pill-shaped)
• Update colors to whiteAlpha for dark theme compatibility
• Adjust padding and hover effects for minimal border style
• Update focus state shadow to match dark theme

app/components/Footer/HelpUsButton.tsx


Grey Divider

Qodo Logo

@4tal 4tal merged commit edb5d24 into 4tals:main Feb 8, 2026
4 of 5 checks passed
@qodo-code-review
Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (2) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Footer missing use client 🐞 Bug ✓ Correctness
Description
Footer calls useBreakpointValue (a React hook) but the module is not marked with `"use
  client"`, which is required if it’s imported by a Server Component.
• app/layout.tsx (server by default) imports Footer; this can trigger Next.js build/runtime
  errors about using client-only hooks in Server Components / missing client boundary.
• This is high impact because it can prevent the app from building or rendering correctly depending
  on Next’s module graph/tree-shaking.
Code

app/components/Footer/Footer.tsx[R30-32]

	const isMobile = useBreakpointValue({ base: true, md: false });
-	const socialIconSize = useBreakpointValue({ base: "20px", md: "24px" });
-	const showHelpButton = useBreakpointValue({ base: false, md: true });
+	const socialIconSize = useBreakpointValue({ base: "18px", md: "20px" });

-	// Mobile layout - stack vertically
-	if (isMobile) {
-		return (
-			<Box as="footer" {...FOOTER_STYLES.container}>
-				<Container maxW="container.xl" {...FOOTER_STYLES.content}>
-					<VStack spacing={3} align="center">
-						{/* Hebrew text and reverse image */}
-						<VStack spacing={2} align="center">
-							<Text {...FOOTER_STYLES.hebrewText}>
Evidence
Footer.tsx is currently not a client module (no "use client" directive at the top) but uses
Chakra’s useBreakpointValue. Separately, the server app/layout.tsx imports Footer, which
requires Footer to be a client component to safely use hooks under Next’s app router rules.

app/components/Footer/Footer.tsx[1-33]
app/layout.tsx[1-10]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`Footer` uses Chakra hooks (`useBreakpointValue`) but the module is not explicitly marked as a client component. In the Next.js app router, this becomes a problem when a Server Component imports it (currently `app/layout.tsx` imports `Footer`).

### Issue Context
This can lead to Next.js build/runtime errors around client-only hooks being used from Server Components, depending on module graph evaluation.

### Fix Focus Areas
- app/components/Footer/Footer.tsx[1-33]
- app/layout.tsx[1-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. reverseImageUrl misleading name 📘 Rule violation ✓ Correctness
Description
FOOTER_CONFIG.reverseImageUrl is named like it points to an image resource, but it is used as a
  link to a Twitter/X post.
• This makes the code less self-documenting and can mislead future changes (e.g., someone may try to
  treat it as an image URL).
• Renaming it to something like reversePostUrl/reverseSourceUrl would better match its intent
  and usage.
Code

app/components/Footer/Footer.tsx[R20-60]

const FOOTER_CONFIG = {
	hebrewText: "הופכים עליהם, טובים אותם",
	reverseImageUrl:
		"https://twitter.com/kann/status/1712897481837539810?t=kxXrXgX59tp1yPnrYiS4Iw&s=19",
	reverseImageAlt: "Reverse Initiative",
	reverseImageSrc: "/images/reverse.png",
-} as const;
-
-const FOOTER_STYLES = {
-	container: {
-		borderTopWidth: "1px",
-		borderColor: "gray.200",
-		backgroundColor: "white",
-		position: "sticky" as const,
-		bottom: 0,
-		zIndex: 999,
-		boxShadow: "0 -2px 10px rgba(0, 0, 0, 0.1)",
-	},
-	content: {
-		fontFamily: "Roboto, sans-serif",
-		py: { base: 3, md: 4 },
-		px: { base: 4, md: 6 },
-	},
-	hebrewText: {
-		textAlign: "center" as const,
-		fontSize: { base: "12px", md: "14px" },
-		color: "gray.600",
-		fontWeight: "medium",
-	},
-	imageBox: {
-		boxSize: { base: "28px", md: "36px" },
-		borderRadius: "md",
-		overflow: "hidden",
-		transition: "transform 0.2s ease",
-		_hover: {
-			transform: "scale(1.05)",
-		},
-	},
-	socialButton: {
-		size: { base: "sm", md: "md" },
-		variant: "ghost",
-		borderRadius: "full",
-		transition: "all 0.2s ease",
-		_hover: {
-			transform: "translateY(-2px)",
-			boxShadow: "md",
-		},
-		_focus: {
-			boxShadow: "outline",
-		},
-	},
+	copyrightText: "Links For Israel",
} as const;

export function Footer() {
-	// Responsive values
	const isMobile = useBreakpointValue({ base: true, md: false });
-	const socialIconSize = useBreakpointValue({ base: "20px", md: "24px" });
-	const showHelpButton = useBreakpointValue({ base: false, md: true });
+	const socialIconSize = useBreakpointValue({ base: "18px", md: "20px" });

-	// Mobile layout - stack vertically
-	if (isMobile) {
-		return (
-			<Box as="footer" {...FOOTER_STYLES.container}>
-				<Container maxW="container.xl" {...FOOTER_STYLES.content}>
-					<VStack spacing={3} align="center">
-						{/* Hebrew text and reverse image */}
-						<VStack spacing={2} align="center">
-							<Text {...FOOTER_STYLES.hebrewText}>
+	return (
+		<Box
+			as="footer"
+			position="sticky"
+			bottom={0}
+			zIndex={999}
+			bg="linear-gradient(135deg, #1a1a2e 0%, #16213e 100%)"
+			borderTop="1px solid"
+			borderColor="whiteAlpha.100"
+			backdropFilter="blur(10px)"
+		>
+			<Container
+				maxW="container.xl"
+				py={{ base: 4, md: 5 }}
+				px={{ base: 4, md: 8 }}
+			>
+				{isMobile ? (
+					// Mobile Layout
+					<VStack spacing={4}>
+						{/* Hebrew motto with subtle styling */}
+						<HStack spacing={3} align="center">
+							<Link
+								href={FOOTER_CONFIG.reverseImageUrl}
+								isExternal
+								aria-label="קישור לפוסט המקורי"
+								_hover={{ transform: "scale(1.1)" }}
+								transition="transform 0.2s ease"
+							>
Evidence
Compliance ID 2 requires identifiers to match their purpose and not be misleading. Here,
reverseImageUrl implies an image URL but is used as an external post link (href) while the
actual image is sourced from reverseImageSrc.

Rule 2: Generic: Meaningful Naming and Self-Documenting Code
app/components/Footer/Footer.tsx[20-27]
app/components/Footer/Footer.tsx[54-66]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`FOOTER_CONFIG.reverseImageUrl` is misleadingly named: it is used as a link to a post (href), not an image URL.

## Issue Context
The footer uses `reverseImageSrc` for the actual image source while `reverseImageUrl` is the external destination. Per naming compliance, identifiers should reflect intent.

## Fix Focus Areas
- app/components/Footer/Footer.tsx[20-66]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. HelpUsButton name mismatch 📘 Rule violation ✓ Correctness
Description
• The component name HelpUsButton no longer matches the UI copy and behavior, which now presents a
  < Contribute /> call-to-action.
• This reduces self-documentation and makes it harder to discover the component by intent when
  searching the codebase.
• Consider renaming the component (and file, if appropriate) to something like
  ContributeButton/ContributeLink and updating imports/usages.
Code

app/components/Footer/HelpUsButton.tsx[R7-39]

export const HelpUsButton = (): JSX.Element => {
	return (
		<Link
			href="https://github.com/4tals/LinksForIsrael/blob/main/docs/contribute.md"
			isExternal
			sx={{
-				fontFamily: "'Consolas', 'Monaco', 'Source Code Pro', monospace",
-				backgroundColor: "blue.500", // Standard blue color
-				color: "white",
-				padding: { base: "8px 18px", md: "6px 12px" },
-				fontSize: { base: "xs", md: "sm" }, //bas Smaller font size on mobile (xs) and slightly larger on tablet and above (sm)
-				border: "none",
-				borderRadius: "8px",
+				fontFamily: "'JetBrains Mono', 'Fira Code', 'Consolas', monospace",
+				fontSize: { base: "xs", md: "sm" },
+				fontWeight: "500",
+				letterSpacing: "0.5px",
+				color: "whiteAlpha.900",
+				bg: "transparent",
+				border: "1px solid",
+				borderColor: "whiteAlpha.300",
+				borderRadius: "full",
+				px: { base: 4, md: 5 },
+				py: { base: 2, md: 2 },
				textDecoration: "none",
-				boxShadow: "0px 4px 12px rgba(0, 0, 0, 0.1)",
-				transition: "transform 0.3s ease, background-color 0.3s ease",
+				transition: "all 0.3s ease",
				_hover: {
-					backgroundColor: "blue.600",
-					transform: "translateY(-2px)",
-					boxShadow: "0px 6px 16px rgba(0, 0, 0, 0.2)",
+					bg: "whiteAlpha.100",
+					borderColor: "whiteAlpha.500",
+					transform: "translateY(-1px)",
+					textDecoration: "none",
				},
				_focus: {
					outline: "none",
-					boxShadow: "0 0 0 3px rgba(66, 153, 225, 0.6)",
+					boxShadow: "0 0 0 2px rgba(255, 255, 255, 0.2)",
				},
			}}
		>
-			{displayText}
+			{"<"} Contribute {"/>"}
		</Link>
Evidence
Compliance ID 2 requires meaningful, intent-revealing identifiers. The exported component is named
HelpUsButton, but it renders the label < Contribute /> and links to contribution docs,
indicating a mismatch between identifier and intent.

Rule 2: Generic: Meaningful Naming and Self-Documenting Code
app/components/Footer/HelpUsButton.tsx[7-11]
app/components/Footer/HelpUsButton.tsx[37-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `HelpUsButton` identifier no longer matches the rendered call-to-action (`&lt; Contribute /&gt;`) and destination (contribution docs).

## Issue Context
Naming compliance requires self-documenting identifiers; mismatched naming makes maintenance and discovery harder.

## Fix Focus Areas
- app/components/Footer/HelpUsButton.tsx[7-39]
- app/components/Footer/Footer.tsx[18-180]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Mobile social links overflow 🐞 Bug ✓ Correctness
Description
• The mobile social links are rendered in a single HStack without wrapping (flexWrap), so on
  small viewports the row can overflow and make icons partially inaccessible.
• This is a regression risk because socialLinks already contains 5 items, and any addition or
  larger accessibility font/spacing settings increases overflow likelihood.
Code

app/components/Footer/Footer.tsx[R78-107]

+						{/* Social links */}
+						<HStack spacing={1}>
+							{socialLinks.map((link) => (
+								<IconButton
+									key={link.href}
+									as={Link}
+									href={link.href}
									isExternal
-									aria-label="קישור לפוסט המקורי בטוויטר"
-								>
-									<Box {...FOOTER_STYLES.imageBox}>
+									aria-label={link.alt}
+									icon={
										<Image
-											src={FOOTER_CONFIG.reverseImageSrc}
-											alt={FOOTER_CONFIG.reverseImageAlt}
-											width={FOOTER_STYLES.imageBox.boxSize}
-											height={FOOTER_STYLES.imageBox.boxSize}
-											loading="lazy"
+											src={link.imgSrc}
+											alt={link.alt}
+											boxSize={socialIconSize}
+											filter="brightness(0) invert(1)"
+											opacity={0.8}
										/>
-									</Box>
-								</Link>
-							</Tooltip>
-						</VStack>
-
-						{/* Social media links */}
-						<HStack spacing={1} justify="center" wrap="wrap">
-							{socialLinks.map((link, index) => (
-								<Tooltip key={link.href} label={link.alt} placement="top">
-									<IconButton
-										as={Link}
-										href={link.href}
-										isExternal
-										aria-label={`עבור ל${link.alt}`}
-										icon={
-											<Image
-												src={link.imgSrc}
-												alt={link.alt}
-												boxSize={socialIconSize}
-												loading="lazy"
-											/>
-										}
-										{...FOOTER_STYLES.socialButton}
-									/>
-								</Tooltip>
+									}
+									variant="ghost"
+									size="sm"
+									borderRadius="full"
+									color="whiteAlpha.800"
+									_hover={{
+										bg: "whiteAlpha.200",
+										transform: "translateY(-2px)",
+									}}
+									transition="all 0.2s ease"
+								/>
							))}
						</HStack>
Evidence
The mobile footer uses an HStack for all social icons without any wrap/flexWrap behavior. The
underlying socialLinks list has 5 entries, which is enough to overflow narrow screens depending on
icon/button sizing and container padding.

app/components/Footer/Footer.tsx[78-107]
app/utils/consts.ts[1-30]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
On mobile, the social icon row does not wrap. This can overflow narrow screens and hide icons.

### Issue Context
`socialLinks` already includes 5 entries; button sizes + padding can exceed small viewport widths.

### Fix Focus Areas
- app/components/Footer/Footer.tsx[78-107]
- app/utils/consts.ts[1-30]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
5. Footer images eager-load 🐞 Bug ➹ Performance
Description
• Footer images (reverse logo + social icons) no longer specify loading="lazy", so browsers may
  eagerly fetch these assets even though the footer is not primary content.
• This can increase initial network contention (especially since several icons are remote URLs),
  causing minor but real performance regressions on slower connections.
Code

app/components/Footer/Footer.tsx[R54-95]

+							<Link
+								href={FOOTER_CONFIG.reverseImageUrl}
+								isExternal
+								aria-label="קישור לפוסט המקורי"
+								_hover={{ transform: "scale(1.1)" }}
+								transition="transform 0.2s ease"
+							>
+								<Image
+									src={FOOTER_CONFIG.reverseImageSrc}
+									alt={FOOTER_CONFIG.reverseImageAlt}
+									boxSize="28px"
+									borderRadius="md"
+								/>
+							</Link>
+							<Text
+								fontSize="sm"
+								fontWeight="500"
+								color="whiteAlpha.900"
+								letterSpacing="wide"
+							>
								{FOOTER_CONFIG.hebrewText}
							</Text>
-							<Tooltip label="לפוסט המקורי בטוויטר" placement="top">
-								<Link
-									href={FOOTER_CONFIG.reverseImageUrl}
+						</HStack>
+
+						{/* Social links */}
+						<HStack spacing={1}>
+							{socialLinks.map((link) => (
+								<IconButton
+									key={link.href}
+									as={Link}
+									href={link.href}
									isExternal
-									aria-label="קישור לפוסט המקורי בטוויטר"
-								>
-									<Box {...FOOTER_STYLES.imageBox}>
+									aria-label={link.alt}
+									icon={
										<Image
-											src={FOOTER_CONFIG.reverseImageSrc}
-											alt={FOOTER_CONFIG.reverseImageAlt}
-											width={FOOTER_STYLES.imageBox.boxSize}
-											height={FOOTER_STYLES.imageBox.boxSize}
-											loading="lazy"
+											src={link.imgSrc}
+											alt={link.alt}
+											boxSize={socialIconSize}
+											filter="brightness(0) invert(1)"
+											opacity={0.8}
										/>
-									</Box>
-								</Link>
-							</Tooltip>
-						</VStack>
-
-						{/* Social media links */}
-						<HStack spacing={1} justify="center" wrap="wrap">
-							{socialLinks.map((link, index) => (
-								<Tooltip key={link.href} label={link.alt} placement="top">
-									<IconButton
-										as={Link}
-										href={link.href}
-										isExternal
-										aria-label={`עבור ל${link.alt}`}
-										icon={
-											<Image
-												src={link.imgSrc}
-												alt={link.alt}
-												boxSize={socialIconSize}
-												loading="lazy"
-											/>
-										}
-										{...FOOTER_STYLES.socialButton}
-									/>
-								</Tooltip>
+									}
Evidence
The Image usages in the footer no longer include a lazy-loading hint. Several socialLinks images
point to remote URLs, which can add extra early requests and compete with more important page
resources.

app/components/Footer/Footer.tsx[54-67]
app/components/Footer/Footer.tsx[87-95]
app/utils/consts.ts[7-29]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Footer images are likely being fetched eagerly; reintroducing lazy loading reduces unnecessary early network requests.

### Issue Context
Several social icons are loaded from remote URLs.

### Fix Focus Areas
- app/components/Footer/Footer.tsx[54-67]
- app/components/Footer/Footer.tsx[87-95]
- app/components/Footer/Footer.tsx[124-130]
- app/utils/consts.ts[7-29]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines 30 to 32
const isMobile = useBreakpointValue({ base: true, md: false });
const socialIconSize = useBreakpointValue({ base: "20px", md: "24px" });
const showHelpButton = useBreakpointValue({ base: false, md: true });
const socialIconSize = useBreakpointValue({ base: "18px", md: "20px" });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Footer missing use client 🐞 Bug ✓ Correctness

Footer calls useBreakpointValue (a React hook) but the module is not marked with `"use
  client"`, which is required if it’s imported by a Server Component.
• app/layout.tsx (server by default) imports Footer; this can trigger Next.js build/runtime
  errors about using client-only hooks in Server Components / missing client boundary.
• This is high impact because it can prevent the app from building or rendering correctly depending
  on Next’s module graph/tree-shaking.
Agent Prompt
### Issue description
`Footer` uses Chakra hooks (`useBreakpointValue`) but the module is not explicitly marked as a client component. In the Next.js app router, this becomes a problem when a Server Component imports it (currently `app/layout.tsx` imports `Footer`).

### Issue Context
This can lead to Next.js build/runtime errors around client-only hooks being used from Server Components, depending on module graph evaluation.

### Fix Focus Areas
- app/components/Footer/Footer.tsx[1-33]
- app/layout.tsx[1-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants