Skip to content

Add macro breakdown bar with 3-color visualization#51

Closed
grepsedawk wants to merge 1 commit into
mainfrom
feature/protein-progress-bar
Closed

Add macro breakdown bar with 3-color visualization#51
grepsedawk wants to merge 1 commit into
mainfrom
feature/protein-progress-bar

Conversation

@grepsedawk

Copy link
Copy Markdown
Owner

Creates a visual breakdown bar showing carbs (blue), protein (green),
and fat (orange) proportions based on caloric contribution. Includes
labels showing gram amounts and percentages for each macro.

Features:

  • Proportional width based on calories (carbs/protein = 4cal/g, fat = 9cal/g)
  • Color-coded sections with smooth transitions
  • Individual labels with colored indicators
  • Displays both grams and percentage for each macro

🤖 Generated with Claude Code

Co-Authored-By: Claude [email protected]

Creates a visual breakdown bar showing carbs (blue), protein (green),
and fat (orange) proportions based on caloric contribution. Includes
labels showing gram amounts and percentages for each macro.

Features:
- Proportional width based on calories (carbs/protein = 4cal/g, fat = 9cal/g)
- Color-coded sections with smooth transitions
- Individual labels with colored indicators
- Displays both grams and percentage for each macro

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Copilot AI review requested due to automatic review settings August 11, 2025 04:00

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Summary of Changes

Hello @grepsedawk, 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 introduces a new visual component to display the breakdown of macronutrients (carbs, protein, and fat) based on their caloric contribution. This bar provides a quick, color-coded overview of macro proportions, enhancing the user's ability to track their nutritional intake.

Highlights

  • New Macro Breakdown Bar: I've implemented a createMacroBreakdownBar method that generates a visual representation of carbohydrate, protein, and fat proportions.
  • Caloric Proportionality: The bar's sections are proportionally sized based on the caloric contribution of each macro (4 cal/g for carbs/protein, 9 cal/g for fat).
  • Visual Cues and Labels: The bar features distinct color-coded sections (blue for carbs, green for protein, orange for fat) with smooth transitions, accompanied by labels showing both gram amounts and percentage contributions for each macro.
  • Integration into ShowTotals: The newly created macro breakdown bar is now integrated into the ShowTotals component, appearing alongside existing progress indicators.
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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

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 issue 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 or fill out our survey to provide feedback.

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.

@github-actions

Copy link
Copy Markdown

🚀 PR Preview deployed!

You can preview this PR at: https://grepsedawk.github.io/planmy.hike/pr-51/

The preview will update automatically when you push new commits to this PR.


This comment was automatically generated by the PR Preview workflow.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds a visual macro breakdown bar to the food planning interface that displays carbohydrate, protein, and fat proportions based on their caloric contributions. The visualization uses a three-color bar chart with blue for carbs, green for protein, and orange for fat, along with detailed labels showing both gram amounts and percentages.

Key Changes

  • Adds a new macro breakdown visualization component to the food planning totals section
  • Implements proportional width calculation based on macro caloric values (carbs/protein = 4cal/g, fat = 9cal/g)
  • Creates color-coded labels with indicators showing grams and percentages for each macronutrient

Comment thread pages/food/ShowTotals.js
Comment on lines +172 to +175
// Calculate percentages
const carbPercent = totalMacroCalories > 0 ? (carbCalories / totalMacroCalories) * 100 : 0
const proteinPercent = totalMacroCalories > 0 ? (proteinCalories / totalMacroCalories) * 100 : 0
const fatPercent = totalMacroCalories > 0 ? (fatCalories / totalMacroCalories) * 100 : 0

Copilot AI Aug 11, 2025

Copy link

Choose a reason for hiding this comment

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

Division by zero protection is inconsistent. If totalMacroCalories is 0, all percentages will be 0, but the bar sections will still have width styles applied. This could lead to unexpected visual behavior when no foods are added.

Suggested change
// Calculate percentages
const carbPercent = totalMacroCalories > 0 ? (carbCalories / totalMacroCalories) * 100 : 0
const proteinPercent = totalMacroCalories > 0 ? (proteinCalories / totalMacroCalories) * 100 : 0
const fatPercent = totalMacroCalories > 0 ? (fatCalories / totalMacroCalories) * 100 : 0
// If there are no macro calories, do not render the bar
if (totalMacroCalories === 0) {
return null
}
// Calculate percentages
const carbPercent = (carbCalories / totalMacroCalories) * 100
const proteinPercent = (proteinCalories / totalMacroCalories) * 100
const fatPercent = (fatCalories / totalMacroCalories) * 100

Copilot uses AI. Check for mistakes.
Comment thread pages/food/ShowTotals.js
Comment on lines +177 to +216
// Label
const labelEl = document.createElement("div")
labelEl.style.cssText =
"font-size: var(--font-size-sm); font-weight: var(--font-weight-medium); color: var(--text-primary); margin-bottom: var(--spacing-2);"
labelEl.textContent = "Macro Breakdown"

// Bar container
const barContainer = document.createElement("div")
barContainer.style.cssText = `
display: flex;
height: 24px;
background-color: var(--background-tertiary);
border-radius: var(--radius-md);
overflow: hidden;
`

// Carbs section
const carbsSection = document.createElement("div")
carbsSection.style.cssText = `
background-color: var(--primary);
width: ${carbPercent}%;
transition: all 0.3s ease;
`

// Protein section
const proteinSection = document.createElement("div")
proteinSection.style.cssText = `
background-color: var(--success);
width: ${proteinPercent}%;
transition: all 0.3s ease;
`

// Fat section
const fatSection = document.createElement("div")
fatSection.style.cssText = `
background-color: var(--warning);
width: ${fatPercent}%;
transition: all 0.3s ease;
`

Copilot AI Aug 11, 2025

Copy link

Choose a reason for hiding this comment

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

When carbPercent is 0, the CSS width will be '0%' which is valid, but when totalMacroCalories is 0, all three sections will have 0% width, potentially causing layout issues. Consider adding a check to hide the entire bar when no macro data exists.

Suggested change
// Label
const labelEl = document.createElement("div")
labelEl.style.cssText =
"font-size: var(--font-size-sm); font-weight: var(--font-weight-medium); color: var(--text-primary); margin-bottom: var(--spacing-2);"
labelEl.textContent = "Macro Breakdown"
// Bar container
const barContainer = document.createElement("div")
barContainer.style.cssText = `
display: flex;
height: 24px;
background-color: var(--background-tertiary);
border-radius: var(--radius-md);
overflow: hidden;
`
// Carbs section
const carbsSection = document.createElement("div")
carbsSection.style.cssText = `
background-color: var(--primary);
width: ${carbPercent}%;
transition: all 0.3s ease;
`
// Protein section
const proteinSection = document.createElement("div")
proteinSection.style.cssText = `
background-color: var(--success);
width: ${proteinPercent}%;
transition: all 0.3s ease;
`
// Fat section
const fatSection = document.createElement("div")
fatSection.style.cssText = `
background-color: var(--warning);
width: ${fatPercent}%;
transition: all 0.3s ease;
`
// Only render macro breakdown bar if there is macro data
if (totalMacroCalories > 0) {
// Label
const labelEl = document.createElement("div")
labelEl.style.cssText =
"font-size: var(--font-size-sm); font-weight: var(--font-weight-medium); color: var(--text-primary); margin-bottom: var(--spacing-2);"
labelEl.textContent = "Macro Breakdown"
// Bar container
const barContainer = document.createElement("div")
barContainer.style.cssText = `
display: flex;
height: 24px;
background-color: var(--background-tertiary);
border-radius: var(--radius-md);
overflow: hidden;
`
// Carbs section
const carbsSection = document.createElement("div")
carbsSection.style.cssText = `
background-color: var(--primary);
width: ${carbPercent}%;
transition: all 0.3s ease;
`
// Protein section
const proteinSection = document.createElement("div")
proteinSection.style.cssText = `
background-color: var(--success);
width: ${proteinPercent}%;
transition: all 0.3s ease;
`
// Fat section
const fatSection = document.createElement("div")
fatSection.style.cssText = `
background-color: var(--warning);
width: ${fatPercent}%;
transition: all 0.3s ease;
`
// (Presumably, code to append these elements to the DOM follows here)
}

Copilot uses AI. Check for mistakes.

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

Copy link
Copy Markdown

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 introduces a new macro breakdown bar, which is a valuable visualization. The implementation is functional, but there are several opportunities for improvement in terms of maintainability, security, and code quality. My review includes suggestions to refactor duplicated code, replace 'magic numbers' with constants, and avoid using innerHTML for better security. These changes will make the new component more robust and easier to maintain.

Comment thread pages/food/ShowTotals.js
Comment on lines +232 to +251
const carbLabel = document.createElement("div")
carbLabel.style.cssText = "display: flex; align-items: center; gap: var(--spacing-1);"
carbLabel.innerHTML = `
<div style="width: 12px; height: 12px; background-color: var(--primary); border-radius: 2px;"></div>
<span>Carbs: ${totalCarbs.toFixed(1)}g (${carbPercent.toFixed(0)}%)</span>
`

const proteinLabel = document.createElement("div")
proteinLabel.style.cssText = "display: flex; align-items: center; gap: var(--spacing-1);"
proteinLabel.innerHTML = `
<div style="width: 12px; height: 12px; background-color: var(--success); border-radius: 2px;"></div>
<span>Protein: ${totalProtein.toFixed(1)}g (${proteinPercent.toFixed(0)}%)</span>
`

const fatLabel = document.createElement("div")
fatLabel.style.cssText = "display: flex; align-items: center; gap: var(--spacing-1);"
fatLabel.innerHTML = `
<div style="width: 12px; height: 12px; background-color: var(--warning); border-radius: 2px;"></div>
<span>Fat: ${totalFat.toFixed(1)}g (${fatPercent.toFixed(0)}%)</span>
`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The creation of these labels is repetitive and uses innerHTML, which can be a security risk (Cross-Site Scripting). It's better to create a helper function that programmatically builds the DOM elements using document.createElement and textContent. This makes the code safer, more maintainable, and eliminates duplication.

    const createMacroLabel = (name, total, percent, colorVar) => {
      const label = document.createElement("div");
      label.style.cssText = "display: flex; align-items: center; gap: var(--spacing-1);";

      const colorBox = document.createElement("div");
      colorBox.style.cssText = `width: 12px; height: 12px; background-color: ${colorVar}; border-radius: 2px;`;
      label.appendChild(colorBox);

      const text = document.createElement("span");
      text.textContent = `${name}: ${total.toFixed(1)}g (${percent.toFixed(0)}%)`;
      label.appendChild(text);

      return label;
    };

    const carbLabel = createMacroLabel("Carbs", totalCarbs, carbPercent, "var(--primary)");
    const proteinLabel = createMacroLabel("Protein", totalProtein, proteinPercent, "var(--success)");
    const fatLabel = createMacroLabel("Fat", totalFat, fatPercent, "var(--warning)");

Comment thread pages/food/ShowTotals.js
Comment on lines +167 to +169
const carbCalories = totalCarbs * 4
const proteinCalories = totalProtein * 4
const fatCalories = totalFat * 9

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

These hardcoded calorie values are 'magic numbers'. Defining them as named constants makes the code more readable and easier to maintain. You could define a constant object at the top of the function and use it here:

const CALORIES_PER_GRAM = { CARB: 4, PROTEIN: 4, FAT: 9 };
Suggested change
const carbCalories = totalCarbs * 4
const proteinCalories = totalProtein * 4
const fatCalories = totalFat * 9
const carbCalories = totalCarbs * CALORIES_PER_GRAM.CARB;
const proteinCalories = totalProtein * CALORIES_PER_GRAM.PROTEIN;
const fatCalories = totalFat * CALORIES_PER_GRAM.FAT;

Comment thread pages/food/ShowTotals.js
Comment on lines +194 to +219
const carbsSection = document.createElement("div")
carbsSection.style.cssText = `
background-color: var(--primary);
width: ${carbPercent}%;
transition: all 0.3s ease;
`

// Protein section
const proteinSection = document.createElement("div")
proteinSection.style.cssText = `
background-color: var(--success);
width: ${proteinPercent}%;
transition: all 0.3s ease;
`

// Fat section
const fatSection = document.createElement("div")
fatSection.style.cssText = `
background-color: var(--warning);
width: ${fatPercent}%;
transition: all 0.3s ease;
`

barContainer.appendChild(carbsSection)
barContainer.appendChild(proteinSection)
barContainer.appendChild(fatSection)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The creation of the bar sections for carbs, protein, and fat is very repetitive. This can be refactored into a loop to reduce duplication and improve maintainability. This also makes it easier to add or remove macro sections in the future.

Additionally, this approach still uses inline styles. For better separation of concerns, consider moving these styles to a dedicated CSS class.

Suggested change
const carbsSection = document.createElement("div")
carbsSection.style.cssText = `
background-color: var(--primary);
width: ${carbPercent}%;
transition: all 0.3s ease;
`
// Protein section
const proteinSection = document.createElement("div")
proteinSection.style.cssText = `
background-color: var(--success);
width: ${proteinPercent}%;
transition: all 0.3s ease;
`
// Fat section
const fatSection = document.createElement("div")
fatSection.style.cssText = `
background-color: var(--warning);
width: ${fatPercent}%;
transition: all 0.3s ease;
`
barContainer.appendChild(carbsSection)
barContainer.appendChild(proteinSection)
barContainer.appendChild(fatSection)
const macros = [
{ percent: carbPercent, color: 'var(--primary)' },
{ percent: proteinPercent, color: 'var(--success)' },
{ percent: fatPercent, color: 'var(--warning)' },
];
macros.forEach(macro => {
const section = document.createElement("div");
section.style.cssText = `
background-color: ${macro.color};
width: ${macro.percent}%;
transition: all 0.3s ease;
`;
barContainer.appendChild(section);
});

@grepsedawk

Copy link
Copy Markdown
Owner Author

Please fix the changes suggested by gemini

@grepsedawk grepsedawk closed this May 21, 2026
github-actions Bot pushed a commit that referenced this pull request May 21, 2026
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