Skip to content

Improve Contributors Button UI and Landing Page Visual Polish - #128

Open
broskell wants to merge 3 commits into
Sahilll94:mainfrom
broskell:improve-contributors-button
Open

Improve Contributors Button UI and Landing Page Visual Polish#128
broskell wants to merge 3 commits into
Sahilll94:mainfrom
broskell:improve-contributors-button

Conversation

@broskell

Copy link
Copy Markdown

Pull Request Description

Summary

This pull request improves the visual styling of the Contributors button in the landing page navbar.
A new reusable .btn-contributors CSS class was added and applied to the Contributors link in Hero.jsx to make it more modern, visually prominent, and interactive.

Type of Change

  • UI/UX improvement

Related Issues

  • Related to #N/A

Motivation and Context

Previously, the Contributors link appeared as plain text in the navigation bar. Since the Contributors page is important for open-source participation, making it visually distinct improves discoverability and enhances the overall landing page design.

Changes Made

  • Added a reusable .btn-contributors style in src/index.css
  • Applied the new button class to the Contributors link in src/pages/hero/Hero.jsx
  • Added hover animation and focus styles for better user interaction and accessibility
  • Ensured compatibility with the existing Tailwind styling system

Screenshots (if applicable)

Before:
Plain text "Contributors" link in navbar.

After:
Styled Contributors button with improved visibility and hover interaction.

Testing

  • I have tested these changes locally
  • I have added tests that prove my fix is effective or that my feature works
  • All new and existing tests pass
  • I have tested the changes on different screen sizes (for UI changes)
  • I have tested in both light and dark mode (for UI changes)

Code Quality

  • My code follows the existing code style of this project
  • I have performed a self-review of my own code
  • I have commented my code where necessary
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors

Deployment

  • These changes require no deployment steps

Breaking Changes

This change does not introduce any breaking changes.

Additional Notes

The styling changes were implemented using Tailwind-compatible CSS and do not modify any existing functionality.

Screenshots

Before
before

*After
after

@vercel

vercel Bot commented Mar 11, 2026

Copy link
Copy Markdown

@broskell is attempting to deploy a commit to the Sahil's projects Team on Vercel.

A member of the Team first needs to authorize it.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request focuses on enhancing the visual appeal and user experience of the application's landing page, particularly by modernizing the 'Contributors' button and applying general UI polish. Concurrently, it refactors the Firebase utility file to improve robustness and simplify authentication logic, ensuring a more stable and maintainable codebase.

Highlights

  • UI/UX Improvement: The 'Contributors' button on the landing page navbar received a significant visual overhaul, making it more prominent and interactive.
  • New Reusable CSS Class: A new .btn-contributors CSS class was introduced in src/index.css to encapsulate the styling for the improved button, promoting reusability.
  • Interactive Styling: Hover animations and focus styles were added to the new button class, enhancing user interaction and accessibility.
  • General UI Polish: Improvements to typography rendering and new layout polish classes (.main-section, .hero-section, .contributor-card) were added to src/index.css.
  • Firebase Utility Refactoring: The src/utils/firebase.js file was refactored for safer initialization, simplified authentication functions, and removal of redundant account linking logic.
  • Dependency Metadata Update: Multiple dependency entries in package-lock.json were updated to include "peer": true.
Changelog
  • package-lock.json
    • Added 'peer: true' property to several dependency entries.
  • src/index.css
    • Removed unnecessary blank lines for cleaner code.
    • Applied improved typography rendering properties to the body element.
    • Introduced a new .btn-contributors class with comprehensive styling for buttons.
    • Added new layout polish classes: .main-section, .hero-section, and .contributor-card with hover effects.
  • src/pages/hero/Hero.jsx
    • Replaced a set of inline Tailwind classes with the new .btn-contributors class for the 'Contributors' link.
  • src/utils/firebase.js
    • Modified Firebase configuration to safely handle missing environment variables.
    • Implemented a try-catch block for Firebase initialization to prevent errors if configuration is incomplete.
    • Removed the EmailAuthProvider import.
    • Streamlined signInWithGoogle, signInWithGithub, and signInWithTwitter functions by removing complex error handling for account linking and sessionStorage usage.
    • Removed several specific account linking functions (e.g., linkGithubToGoogleAccount) and the getProviderFromMethod utility.
    • Added checks to exported functions to ensure Firebase auth is initialized before use.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request successfully implements the visual styling improvements for the Contributors button and other landing page elements as described. The new CSS classes are well-defined and applied correctly in Hero.jsx. However, there are significant changes in src/utils/firebase.js that appear unrelated to the stated purpose of UI/UX improvement. These changes introduce potential regressions in Firebase authentication error handling and account linking functionality, and their inclusion in this PR makes the review process more complex and increases the risk of unintended side effects.

Comment thread src/utils/firebase.js Outdated
Comment on lines +1 to +128
// Import the necessary Firebase packages
import { initializeApp } from 'firebase/app';
import {
import { initializeApp } from "firebase/app";
import {
getAuth,
GoogleAuthProvider,
GoogleAuthProvider,
GithubAuthProvider,
TwitterAuthProvider,
signInWithPopup,
signInWithPopup,
signOut,
onAuthStateChanged,
fetchSignInMethodsForEmail,
linkWithCredential,
EmailAuthProvider
} from 'firebase/auth';

// Your Firebase configuration
// Replace these values with your actual Firebase project config
// You'll need to create a Firebase project and get these values from the Firebase console
} from "firebase/auth";

// Firebase configuration (from environment variables)
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID
apiKey: import.meta.env.VITE_FIREBASE_API_KEY || "",
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN || "",
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID || "",
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET || "",
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID || "",
appId: import.meta.env.VITE_FIREBASE_APP_ID || "",
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
// Initialize Firebase safely
let app = null;
let auth = null;

try {
if (firebaseConfig.apiKey) {
app = initializeApp(firebaseConfig);
auth = getAuth(app);
} else {
console.warn("Firebase environment variables missing. Running without Firebase.");
}
} catch (error) {
console.error("Firebase initialization failed:", error);
}

// Providers
const googleProvider = new GoogleAuthProvider();
const githubProvider = new GithubAuthProvider();
const twitterProvider = new TwitterAuthProvider();

// Configure Google provider (optional settings)
googleProvider.setCustomParameters({
prompt: 'select_account'
prompt: "select_account",
});

// Configure GitHub provider (optional settings)
githubProvider.setCustomParameters({
allow_signup: 'true'
allow_signup: "true",
});

// Configure Twitter provider (optional settings)
twitterProvider.setCustomParameters({
'lang': 'en'
lang: "en",
});

// Add scopes to GitHub provider
githubProvider.addScope('user:email');
githubProvider.addScope('read:user');
githubProvider.addScope("user:email");
githubProvider.addScope("read:user");

// Google sign-in function
// Google sign in
export const signInWithGoogle = async () => {
try {
const result = await signInWithPopup(auth, googleProvider);
const user = result.user;

// Get the Firebase ID token
const idToken = await user.getIdToken();

// The user info from Google
return {
user,
idToken,
// The Google OAuth access token (can be used to access Google APIs)
credential: GoogleAuthProvider.credentialFromResult(result)
};
} catch (error) {
// Handle Errors here.
console.error("Google sign-in error:", error);

// If the error is about accounts with different credentials,
// store the pending credential for later linking
if (error.code === 'auth/account-exists-with-different-credential') {
const pendingCred = GoogleAuthProvider.credentialFromError(error);

// Store for later use if needed
if (pendingCred) {
sessionStorage.setItem('pendingCredential', JSON.stringify({
providerId: pendingCred.providerId,
signInMethod: pendingCred.signInMethod,
email: error.customData?.email
}));
}
}

throw error;
}
if (!auth) throw new Error("Firebase not configured");

const result = await signInWithPopup(auth, googleProvider);
const user = result.user;
const idToken = await user.getIdToken();

return {
user,
idToken,
credential: GoogleAuthProvider.credentialFromResult(result),
};
};

// GitHub sign-in function
// Github sign in
export const signInWithGithub = async () => {
try {
// Configure GitHub provider to get email
githubProvider.addScope('user:email');

const result = await signInWithPopup(auth, githubProvider);
const user = result.user;

// Get the Firebase ID token
const idToken = await user.getIdToken();

// The user info from GitHub
return {
user,
idToken,
// The GitHub OAuth access token (can be used to access GitHub APIs)
credential: GithubAuthProvider.credentialFromResult(result)
};
} catch (error) {
// Handle Errors here.
console.error("GitHub sign-in error:", error);

// If the error is about accounts with different credentials,
// store the pending credential for later linking
if (error.code === 'auth/account-exists-with-different-credential') {
const pendingCred = GithubAuthProvider.credentialFromError(error);

// Store for later use if needed
if (pendingCred) {
sessionStorage.setItem('pendingCredential', JSON.stringify({
providerId: pendingCred.providerId,
signInMethod: pendingCred.signInMethod,
email: error.customData?.email
}));
}
}

throw error;
}
if (!auth) throw new Error("Firebase not configured");

const result = await signInWithPopup(auth, githubProvider);
const user = result.user;
const idToken = await user.getIdToken();

return {
user,
idToken,
credential: GithubAuthProvider.credentialFromResult(result),
};
};

// Twitter sign-in function
// Twitter sign in
export const signInWithTwitter = async () => {
try {
const result = await signInWithPopup(auth, twitterProvider);
const user = result.user;

// Get the Firebase ID token
const idToken = await user.getIdToken();

// The user info from Twitter
return {
user,
idToken,
// The Twitter OAuth access token (can be used to access Twitter APIs)
credential: TwitterAuthProvider.credentialFromResult(result)
};
} catch (error) {
// Handle Errors here.
console.error("Twitter sign-in error:", error);

// If the error is about accounts with different credentials,
// store the pending credential for later linking
if (error.code === 'auth/account-exists-with-different-credential') {
const pendingCred = TwitterAuthProvider.credentialFromError(error);

// Store for later use if needed
if (pendingCred) {
sessionStorage.setItem('pendingCredential', JSON.stringify({
providerId: pendingCred.providerId,
signInMethod: pendingCred.signInMethod,
email: error.customData?.email
}));
}
}

throw error;
}
if (!auth) throw new Error("Firebase not configured");

const result = await signInWithPopup(auth, twitterProvider);
const user = result.user;
const idToken = await user.getIdToken();

return {
user,
idToken,
credential: TwitterAuthProvider.credentialFromResult(result),
};
};

// Sign out function
// Sign out
export const signOutUser = async () => {
try {
await signOut(auth);
return true;
} catch (error) {
console.error("Sign out error:", error);
throw error;
}
if (!auth) return true;
await signOut(auth);
};

// Auth state listener
export const onAuthStateChangedListener = (callback) => {
if (!auth) return () => {};
return onAuthStateChanged(auth, callback);
};

// Function to check if an email already exists and return sign-in methods
// Check existing account
export const checkExistingAccount = async (email) => {
try {
const methods = await fetchSignInMethodsForEmail(auth, email);
return methods;
} catch (error) {
console.error("Error checking existing account:", error);
throw error;
}
if (!auth) return [];
return await fetchSignInMethodsForEmail(auth, email);
};

/**
* Gets the provider name from the sign-in method string
* @param {string} method - The sign-in method string from Firebase
* @returns {string} The provider name (Google, GitHub, Email, etc.)
*/
export const getProviderFromMethod = (method) => {
switch(method) {
case 'google.com':
return 'Google';
case 'github.com':
return 'GitHub';
case 'twitter.com':
return 'Twitter';
case 'password':
return 'Email/Password';
case 'phone':
return 'Phone';
default:
return method;
}
};

/**
* Attempt to link a new provider to an existing account
* This is useful when a user has accounts with different providers but the same email
* @param {object} currentUser - The currently logged-in Firebase user
* @param {object} credential - The credential from the new provider
* @returns {Promise<object>} The linked user account
*/
// Link accounts
export const linkAccounts = async (currentUser, credential) => {
try {
const result = await linkWithCredential(currentUser, credential);
return result.user;
} catch (error) {
console.error("Error linking accounts:", error);
throw error;
}
};

// For all the link functions
export const linkGithubToGoogleAccount = async (credential) => {
try {
if (!auth.currentUser) {
throw new Error('No user is currently signed in');
}

const result = await linkWithCredential(auth.currentUser, credential);
return result.user;
} catch (error) {
console.error('Error linking GitHub account:', error);
throw error;
}
};

export const linkGoogleToGithubAccount = async (credential) => {
try {
if (!auth.currentUser) {
throw new Error('No user is currently signed in');
}

const result = await linkWithCredential(auth.currentUser, credential);
return result.user;
} catch (error) {
console.error('Error linking Google account:', error);
throw error;
}
};

export const linkTwitterToGoogleAccount = async (credential) => {
try {
if (!auth.currentUser) {
throw new Error('No user is currently signed in');
}

const result = await linkWithCredential(auth.currentUser, credential);
return result.user;
} catch (error) {
console.error('Error linking Twitter account:', error);
throw error;
}
};

export const linkTwitterToGithubAccount = async (credential) => {
try {
if (!auth.currentUser) {
throw new Error('No user is currently signed in');
}

const result = await linkWithCredential(auth.currentUser, credential);
return result.user;
} catch (error) {
console.error('Error linking Twitter account:', error);
throw error;
}
};

export const linkGoogleToTwitterAccount = async (credential) => {
try {
if (!auth.currentUser) {
throw new Error('No user is currently signed in');
}

const result = await linkWithCredential(auth.currentUser, credential);
return result.user;
} catch (error) {
console.error('Error linking Google account:', error);
throw error;
}
};

export const linkGithubToTwitterAccount = async (credential) => {
try {
if (!auth.currentUser) {
throw new Error('No user is currently signed in');
}

const result = await linkWithCredential(auth.currentUser, credential);
return result.user;
} catch (error) {
console.error('Error linking GitHub account:', error);
throw error;
}
return await linkWithCredential(currentUser, credential);
};

export { auth, googleProvider, githubProvider, twitterProvider };
export { auth, googleProvider, githubProvider, twitterProvider }; No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The changes in src/utils/firebase.js are extensive and appear to be a significant refactoring of the Firebase authentication logic. These changes are unrelated to the stated purpose of this pull request, which is to improve the UI and visual polish of the Contributors button and landing page. Including unrelated functional changes in a UI/UX PR makes the review more difficult and increases the risk of introducing bugs in critical areas.

Specifically, the removal of the try-catch blocks that handled auth/account-exists-with-different-credential errors and the associated sessionStorage logic (lines 75-88, 113-128, 153-168 in the original file) represents a potential regression in how the application handles users attempting to sign in with different providers using the same email. If account linking or specific error messages for this scenario were previously supported, this functionality might now be broken or less user-friendly. The removal of EmailAuthProvider and several specific link...To...Account functions also suggests a reduction in supported authentication or linking features without clear justification in the PR description.

Comment thread src/index.css
Comment on lines +125 to 148
/* layout polish */

.main-section {
max-width: 1200px;
margin-inline: auto;
padding-inline: 1.5rem;
}

.hero-section {
background: radial-gradient(
circle at top,
rgba(6,182,212,0.08),
transparent 60%
);
}

.contributor-card {
transition: transform 0.25s ease, box-shadow 0.25s ease;
}

.contributor-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 30px rgba(0,0,0,0.08);
} No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The new CSS classes .main-section, .hero-section, and .contributor-card are defined outside the @layer components block. While this works, it's generally recommended to place custom component styles within @layer components for better organization and to leverage Tailwind's processing capabilities more effectively. Additionally, the box-shadow on :hover for .contributor-card uses a fixed rgba(0,0,0,0.08) color. For better dark mode compatibility, consider using a Tailwind shadow utility class or a CSS variable that adapts to the theme.

@broskell
broskell force-pushed the improve-contributors-button branch from 4f7c189 to 610d325 Compare March 12, 2026 04:12
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.

1 participant