Skip to content

feat: revamp bottom nav UI and enhance theme support#62

Open
kasuncfdo wants to merge 1 commit intomainfrom
kasun/revamp-app-nav
Open

feat: revamp bottom nav UI and enhance theme support#62
kasuncfdo wants to merge 1 commit intomainfrom
kasun/revamp-app-nav

Conversation

@kasuncfdo
Copy link
Contributor

@kasuncfdo kasuncfdo commented Mar 5, 2026

Summary by CodeRabbit

  • New Features

    • Redesigned bottom navigation with smooth animations, theme-aware styling, and responsive pill-shaped layout
    • Added support for dynamic background colors that adapt to theme preferences
  • Style

    • Refined dashboard layout spacing with improved vertical and horizontal padding
    • Enhanced visual consistency with better color handling and brand accent integration

@kasuncfdo kasuncfdo self-assigned this Mar 5, 2026
@kasuncfdo kasuncfdo added the enhancement New feature or request label Mar 5, 2026
@vercel
Copy link

vercel bot commented Mar 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
bitcoin-deepa-tma-bot Ready Ready Preview, Comment Mar 5, 2026 8:35pm

Request Review

@qodo-code-review
Copy link
Contributor

Review Summary by Qodo

Revamp bottom navigation UI with glassmorphism and enhanced theming

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Revamped bottom navigation with glassmorphism design and smooth animations
• Added brand accent color variable for consistent Bitcoin orange styling
• Enhanced theme support with dynamic background color handling
• Improved layout spacing with adjusted padding for bottom nav clearance
Diagram
flowchart LR
  A["Theme System"] -->|"Brand accent variable"| B["CSS Variables"]
  B -->|"Dynamic colors"| C["Bottom Navigation"]
  D["Layout"] -->|"Adjusted padding"| E["Dashboard Layout"]
  E -->|"Clearance"| C
  F["Framer Motion"] -->|"Spring animations"| C
  C -->|"Glassmorphism design"| G["Enhanced UI"]
Loading

Grey Divider

File Changes

1. src/styles/theme.css ✨ Enhancement +7/-0

Add brand accent and body background styling

• Added --brand-accent CSS variable set to Bitcoin orange (#ff9900)
• Added body background-color rule using --tg-theme-bg-color
• Maintains existing theme variable structure for light/dark modes

src/styles/theme.css


2. src/app/context/theme.tsx ✨ Enhancement +5/-0

Add background color CSS variable synchronization

• Added background color handling in updateCSSVariables function
• Sets --tg-theme-bg-color CSS property from Telegram theme params
• Ensures body background color syncs with Telegram theme settings

src/app/context/theme.tsx


3. src/app/dashboard/layout.tsx ✨ Enhancement +1/-1

Adjust layout padding for bottom navigation

• Updated padding from p-5 to px-5 pb-20 pt-5
• Adds bottom padding (pb-20) to prevent content overlap with fixed bottom nav
• Maintains horizontal padding and top padding

src/app/dashboard/layout.tsx


View more (1)
4. src/components/bottomNavigation.tsx ✨ Enhancement +82/-45

Redesign bottom navigation with glassmorphism and animations

• Completely redesigned navigation with glassmorphism pill-shaped container
• Integrated Framer Motion for smooth spring animations on active state
• Added theme-aware colors using useTheme hook for dark/light modes
• Replaced static styling with dynamic inline styles for backdrop blur and shadows
• Active nav item now shows animated gradient background with orange accent
• Improved visual hierarchy with icon glow effect on active state

src/components/bottomNavigation.tsx


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Mar 5, 2026

Code Review by Qodo

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

Grey Divider


Action required

1. useTheme bypasses Zustand store 📘 Rule violation ⛯ Reliability
Description
New UI state (isDark) is read from a React Context (useTheme) instead of the documented global
UI state pattern using the Zustand store at @/lib/store. This introduces an alternative state
source that can diverge from the prescribed architecture and complicate maintenance.
Code

src/components/bottomNavigation.tsx[R8-22]

+import { useTheme } from "@/app/context/theme";

const navItems = [
-    {
-        href: "/dashboard",
-        icon: MdWallet,
-        label: "Wallet",
-    },
-    // {
-    //     href: "/dashboard/invite",
-    //     icon: FaUserPlus,
-    //     label: "Invite",
-    // },
-    {
-        href: "/dashboard/subscription",
-        icon: Sprout,
-        label: "Membership",
-    },
-    {
-        href: "/dashboard/history",
-        icon: MdHistory,
-        label: "History",
-    },
-];
+    { href: "/dashboard", icon: MdWallet, label: "Wallet" },
+    { href: "/dashboard/subscription", icon: Sprout, label: "Membership" },
+    { href: "/dashboard/history", icon: MdHistory, label: "History" },
+] as const;

export default function BottomNavigation() {
    const pathname = usePathname();
+    const { isDark } = useTheme();
+
+    const inactiveColor = isDark ? "rgba(255,255,255,0.35)" : "rgba(0,0,0,0.35)";
+    const pillBg = isDark ? "rgba(0,0,0,0.45)" : "rgba(255,255,255,0.55)";
+    const pillBorder = isDark ? "1px solid rgba(255,255,255,0.09)" : "1px solid rgba(0,0,0,0.09)";
Evidence
Compliance ID 4 requires global UI state to be implemented via the Zustand store at @/lib/store,
but the PR introduces useTheme (React Context) usage in BottomNavigation to drive UI behavior
(isDark).

CLAUDE.md
src/components/bottomNavigation.tsx[8-22]

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

## Issue description
`BottomNavigation` now uses `useTheme` (React Context) to read `isDark`, which bypasses the documented global UI state pattern that requires Zustand (`@/lib/store`) for global UI state.

## Issue Context
The project’s compliance checklist mandates using Zustand for global UI state. Theme mode (`isDark`) is global UI state and is now used to drive navigation UI styling.

## Fix Focus Areas
- src/components/bottomNavigation.tsx[8-25]
- src/lib/store.ts[1-111]
- src/app/context/theme.tsx[28-94]

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



Remediation recommended

2. framer-motion statically imported 📘 Rule violation ➹ Performance
Description
The PR adds a static import of framer-motion in BottomNavigation, which can increase the initial
client bundle size. This should be code-split (or replaced with a lighter CSS animation) if it is
not required for the initial render path.
Code

src/components/bottomNavigation.tsx[R7-72]

+import { motion } from "framer-motion";
+import { useTheme } from "@/app/context/theme";

const navItems = [
-    {
-        href: "/dashboard",
-        icon: MdWallet,
-        label: "Wallet",
-    },
-    // {
-    //     href: "/dashboard/invite",
-    //     icon: FaUserPlus,
-    //     label: "Invite",
-    // },
-    {
-        href: "/dashboard/subscription",
-        icon: Sprout,
-        label: "Membership",
-    },
-    {
-        href: "/dashboard/history",
-        icon: MdHistory,
-        label: "History",
-    },
-];
+    { href: "/dashboard", icon: MdWallet, label: "Wallet" },
+    { href: "/dashboard/subscription", icon: Sprout, label: "Membership" },
+    { href: "/dashboard/history", icon: MdHistory, label: "History" },
+] as const;

export default function BottomNavigation() {
    const pathname = usePathname();
+    const { isDark } = useTheme();
+
+    const inactiveColor = isDark ? "rgba(255,255,255,0.35)" : "rgba(0,0,0,0.35)";
+    const pillBg = isDark ? "rgba(0,0,0,0.45)" : "rgba(255,255,255,0.55)";
+    const pillBorder = isDark ? "1px solid rgba(255,255,255,0.09)" : "1px solid rgba(0,0,0,0.09)";
+    const pillShadow = isDark
+        ? "0 4px 60px rgba(0,0,0,0.45), inset 0 1px 0 rgba(255,255,255,0.06)"
+        : "0 4px 40px rgba(0,0,0,0.12), inset 0 1px 0 rgba(255,255,255,0.8)";

    return (
-        <nav className="fixed bottom-0 left-0 right-0 border-t border-gray-700 bg-tma-bg-secondary">
-            <div className="mx-auto max-w-md">
-                <div className="flex justify-around py-2">
-                    {navItems.map((item) => {
-                        const Icon = item.icon;
-                        const isActive = pathname === item.href;
+        <nav
+            className="fixed bottom-0 left-0 right-0 z-50"
+            style={{
+                background:
+                    "linear-gradient(180deg, transparent 0%, var(--tg-theme-bg-color, #212121) 87.66%)",
+            }}
+        >
+            <div
+                className="mx-auto mb-5 flex w-fit items-center rounded-[120px] p-1"
+                style={{
+                    background: pillBg,
+                    backdropFilter: "blur(25px)",
+                    WebkitBackdropFilter: "blur(25px)",
+                    boxShadow: pillShadow,
+                    border: pillBorder,
+                }}
+            >
+                {navItems.map((item) => {
+                    const Icon = item.icon;
+                    const isActive = pathname === item.href;
+
+                    return (
+                        <Link
+                            key={item.href}
+                            href={item.href}
+                            className="relative flex w-24 flex-col items-center justify-center gap-0.5 py-2"
+                        >
+                            {isActive && (
+                                <motion.span
+                                    layoutId="active-bubble"
+                                    className="absolute inset-0"
+                                    style={{
+                                        borderRadius: 9999,
+                                        background:
+                                            "linear-gradient(160deg, rgba(255,153,0,0.22) 0%, rgba(255,153,0,0.09) 100%)",
+                                        border: "1px solid rgba(255,153,0,0.25)",
+                                        boxShadow:
+                                            "inset 0 1px 0 rgba(255,255,255,0.08)",
+                                    }}
+                                    transition={{
+                                        type: "spring",
+                                        bounce: 0.2,
+                                        duration: 0.45,
+                                    }}
+                                />
Evidence
Compliance ID 6 requires using dynamic imports for code splitting where appropriate; the PR
introduces a static framer-motion import and uses it for the active indicator animation.

CLAUDE.md
src/components/bottomNavigation.tsx[7-72]

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

## Issue description
`framer-motion` is statically imported in `BottomNavigation`, which may unnecessarily bloat the initial client bundle.

## Issue Context
The checklist asks for dynamic imports/code splitting where appropriate for heavy/conditional UI. The animated active indicator is a good candidate to lazy-load or to implement via CSS.

## Fix Focus Areas
- src/components/bottomNavigation.tsx[7-72]

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


3. bg-color var not set 🐞 Bug ✓ Correctness
Description
body and the bottom-nav gradient now depend on --tg-theme-bg-color, but the app only sets that
variable when themeParams.bg_color exists and never sets it in the non-Telegram theme path. This
can produce mismatched/low-contrast UI (e.g., OS light mode → isDark=false nav styles on a
still-dark fallback background).
Code

src/app/context/theme.tsx[R121-124]

+    // Background color — set the CSS var so body background-color picks it up
+    if (params.bg_color) {
+        root.style.setProperty("--tg-theme-bg-color", params.bg_color);
+    }
Evidence
The background CSS variable is optional in the theme params and is only applied conditionally;
meanwhile CSS and the new bottom-nav UI use that variable (with a dark fallback). In the
non-Telegram path, theme state toggles via matchMedia but no code updates --tg-theme-bg-color, so
background remains the fallback while useTheme().isDark changes and drives the new nav colors.

src/app/context/theme.tsx[5-7]
src/app/context/theme.tsx[71-77]
src/app/context/theme.tsx[121-124]
src/styles/theme.css[53-55]
src/components/bottomNavigation.tsx[28-33]

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 UI now uses `--tg-theme-bg-color` for `body` background and for the bottom navigation gradient, but the variable is only set when Telegram sends `themeParams.bg_color` and is never set in the non-Telegram (matchMedia) path. This can lead to inconsistent/low-contrast UI (e.g., theme state becomes `light` while the background stays on the dark fallback).

## Issue Context
- `TelegramThemeParams.bg_color` is optional.
- `ThemeProvider` updates `theme` based on matchMedia when Telegram is not present, but does not update `--tg-theme-bg-color`.
- CSS and bottom nav both consume `--tg-theme-bg-color`.

## Fix Focus Areas
- src/app/context/theme.tsx[71-77]
- src/app/context/theme.tsx[118-125]
- src/styles/theme.css[5-56]
- src/components/bottomNavigation.tsx[28-33]

## Implementation notes (one possible approach)
1. Add a default `--tg-theme-bg-color` in `:root` and a light override in `.light`.
2. In the non-Telegram branch, set `document.documentElement.style.setProperty(&#x27;--tg-theme-bg-color&#x27;, ...)` based on the computed theme (and update it inside the `change` handler).
3. In `updateCSSVariables`, set `--tg-theme-bg-color` even when `params.bg_color` is missing by falling back (e.g., `params.secondary_bg_color`) or a sensible theme default.

ⓘ 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

@coderabbitai
Copy link

coderabbitai bot commented Mar 5, 2026

📝 Walkthrough

Walkthrough

This PR adds theme-aware styling to the bottom navigation component with animated active states and pill-shaped design, introduces Telegram background color support in the theme context, adjusts dashboard layout padding, and establishes brand accent and body background CSS variables for consistent theming across the application.

Changes

Cohort / File(s) Summary
Theme Configuration
src/app/context/theme.tsx, src/styles/theme.css
Added support for Telegram background color (--tg-theme-bg-color) parameter mapping and established new CSS variables for brand accent and global body background fallback.
Dashboard Layout
src/app/dashboard/layout.tsx
Modified padding from uniform (p-5) to differentiated vertical and horizontal spacing (px-5 pb-20 pt-5).
Bottom Navigation Component
src/components/bottomNavigation.tsx
Refactored navigation bar from static rendering to theme-aware, responsive pill-shaped design with framer-motion animations, dynamic gradient backgrounds, and active state bubbles; restructured nav data as const-cast tuple and replaced CSS-driven styling with inline conditional logic.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

Review effort 3/5

Suggested reviewers

  • rayaanr
  • mrcentimetre

Poem

🐰 With pill-shaped nav and colors bright,
Telegram themes now styled just right,
Animations dance with gentle grace,
Brand accents find their perfect place,
A bottom bar of pure delight! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: revamping the bottom navigation UI and enhancing theme support across multiple files including theme.tsx, theme.css, and bottomNavigation.tsx.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch kasun/revamp-app-nav

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment on lines +8 to +22
import { useTheme } from "@/app/context/theme";

const navItems = [
{
href: "/dashboard",
icon: MdWallet,
label: "Wallet",
},
// {
// href: "/dashboard/invite",
// icon: FaUserPlus,
// label: "Invite",
// },
{
href: "/dashboard/subscription",
icon: Sprout,
label: "Membership",
},
{
href: "/dashboard/history",
icon: MdHistory,
label: "History",
},
];
{ href: "/dashboard", icon: MdWallet, label: "Wallet" },
{ href: "/dashboard/subscription", icon: Sprout, label: "Membership" },
{ href: "/dashboard/history", icon: MdHistory, label: "History" },
] as const;

export default function BottomNavigation() {
const pathname = usePathname();
const { isDark } = useTheme();

const inactiveColor = isDark ? "rgba(255,255,255,0.35)" : "rgba(0,0,0,0.35)";
const pillBg = isDark ? "rgba(0,0,0,0.45)" : "rgba(255,255,255,0.55)";
const pillBorder = isDark ? "1px solid rgba(255,255,255,0.09)" : "1px solid rgba(0,0,0,0.09)";
Copy link
Contributor

Choose a reason for hiding this comment

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

Action required

1. usetheme bypasses zustand store 📘 Rule violation ⛯ Reliability

New UI state (isDark) is read from a React Context (useTheme) instead of the documented global
UI state pattern using the Zustand store at @/lib/store. This introduces an alternative state
source that can diverge from the prescribed architecture and complicate maintenance.
Agent Prompt
## Issue description
`BottomNavigation` now uses `useTheme` (React Context) to read `isDark`, which bypasses the documented global UI state pattern that requires Zustand (`@/lib/store`) for global UI state.

## Issue Context
The project’s compliance checklist mandates using Zustand for global UI state. Theme mode (`isDark`) is global UI state and is now used to drive navigation UI styling.

## Fix Focus Areas
- src/components/bottomNavigation.tsx[8-25]
- src/lib/store.ts[1-111]
- src/app/context/theme.tsx[28-94]

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/context/theme.tsx (1)

116-124: ⚠️ Potential issue | 🟡 Minor

Comment is inconsistent with the new behavior.

The comment at line 117 states "Only update text and component colors, not background colors" but the new code block (lines 121-124) explicitly sets --tg-theme-bg-color from params.bg_color. Consider updating the comment to reflect the actual behavior.

📝 Proposed fix
 // Update CSS custom properties with Telegram theme colors
-// Only update text and component colors, not background colors (handled by BotFather settings)
+// Updates text, component, and background colors from Telegram theme params
 function updateCSSVariables(params: TelegramThemeParams) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/context/theme.tsx` around lines 116 - 124, The comment above
updateCSSVariables is outdated: it claims "Only update text and component
colors, not background colors" yet the function now sets the background CSS
variable (--tg-theme-bg-color) when params.bg_color is present; update the
comment to reflect that background colors are also updated (or rephrase to
describe exactly which vars are changed), and ensure the comment references
updateCSSVariables and the --tg-theme-bg-color behavior so readers understand
the function's actual effect.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/app/context/theme.tsx`:
- Around line 116-124: The comment above updateCSSVariables is outdated: it
claims "Only update text and component colors, not background colors" yet the
function now sets the background CSS variable (--tg-theme-bg-color) when
params.bg_color is present; update the comment to reflect that background colors
are also updated (or rephrase to describe exactly which vars are changed), and
ensure the comment references updateCSSVariables and the --tg-theme-bg-color
behavior so readers understand the function's actual effect.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7d70ac8d-3776-4f9b-b209-32399ebb59e4

📥 Commits

Reviewing files that changed from the base of the PR and between e00ece2 and 992cb87.

📒 Files selected for processing (4)
  • src/app/context/theme.tsx
  • src/app/dashboard/layout.tsx
  • src/components/bottomNavigation.tsx
  • src/styles/theme.css

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant