Skip to content

ui: implement gradient color pattern for meeting buttons#76

Merged
NotYuSheng merged 24 commits intomainfrom
ui/meeting-buttons-gradient-color-pattern
Aug 7, 2025
Merged

ui: implement gradient color pattern for meeting buttons#76
NotYuSheng merged 24 commits intomainfrom
ui/meeting-buttons-gradient-color-pattern

Conversation

@NotYuSheng
Copy link
Copy Markdown
Owner

Summary

This PR enhances the visual appeal of meeting buttons by implementing a gradient color pattern that creates a smooth visual flow from light to dark and back, improving the aesthetic hierarchy in the meetings list.


Changes Made

  • Change meeting button colors from simple 1-2-3-4 repeat pattern to gradient pattern
  • Implement gradient pattern: 1-2-3-4-3-2-1-2-3-4-3-2...
  • Pattern repeats every 6 buttons for consistent gradient effect
  • Creates smooth visual flow that improves visual hierarchy

Context / Rationale

The previous simple 1-2-3-4 pattern was repetitive and didn't provide an optimal visual flow. This gradient pattern:

  1. Creates a more sophisticated visual hierarchy
  2. Improves aesthetic appeal with smooth transitions
  3. Maintains consistency while adding visual interest
  4. Enhances user experience when viewing multiple meetings

Related Docs or References

  • UI enhancement focused on improving visual design
  • No functional changes, purely cosmetic improvement

General Checklist

  • I have tested these changes locally
  • I have updated relevant documentation or added comments where needed
  • I have linked relevant issues and tagged reviewers
  • I have followed coding conventions and naming standards

NotYuSheng and others added 24 commits August 6, 2025 09:07
- Add CSS shadow variables for light and dark modes
- Apply shadows to header card, main cards, and buttons
- Add subtle hover animations with lift effect on buttons
- Style transcript entries with shadows and rounded corners
- Enhance visual hierarchy and modern design aesthetics

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add subtle opacity reduction (50%) for disabled buttons
- Include not-allowed cursor for better UX indication
- Prevent hover animations on disabled state
- Clean, minimal approach without color changes

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Slow down particle movement speed from 6 to 2 for subtler motion
- Add organizational color variety to particles using brand palette
- Keep original white connecting lines with full opacity unchanged
- Particles now use: #2998D5, #265289, #75797C, #bba88e, #c42030, #FFFFFF

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed sun icon visibility in light mode (☀️)
- Corrected CSS logic for checked/unchecked states
- Light mode: sun icon on left with blue gradient
- Dark mode: moon icon on right with gray gradient
- Smooth transitions between states with proper icon positioning

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Replace flat colors with subtle linear gradients for visual depth
- Add gradient backgrounds to app container, cards, and components
- Enhance button styling with gradient backgrounds and hover effects
- Improve transcript entries with gradient backgrounds
- Maintain organizational color palette while adding modern visual appeal
- Keep accessibility and contrast standards intact

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add professional styling to model selector dropdown
- Implement proper focus and hover states with organizational colors
- Use solid backgrounds for better cross-browser compatibility
- Improve responsive layout with better spacing and alignment
- Add consistent typography using Barlow font family
- Support both light and dark theme modes

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Replace plain #bba88e borders with subtle gradient border effects
- Use CSS pseudo-elements for sophisticated gradient border technique
- Fix rectangular shadow issue by moving shadows to pseudo-elements
- Apply proper border-radius calculations for clean rounded corners
- Add theme-aware gradient variations for light and dark modes
- Improve visual depth and premium appearance of all cards

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove ugly red color (#c42030) from particle palette
- Increase particle opacity from 1.0 to 0.9 for much sharper appearance
- Make connecting lines more prominent (opacity 0.8, width 2.5px)
- Use darker shade of #bba88e (#8a7c6b) for connecting lines
- Reduce app background opacity to 50-60% so particles show through
- Improve particle backgrounds with more contrasting gradients
- Clean color palette: #2998D5, #265289, #75797C, #bba88e, #FFFFFF

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Convert recording, upload, and transcription buttons to discrete red design
- Use #F4393B for discrete buttons with icon-only interface and tooltips
- Implement prominent transcription button (#D32F2F) when file is uploaded
- Add "Process Audio" text to transcription button for better UX clarity
- Fix CSS specificity issues with \!important to override gradient backgrounds
- Ensure consistent button sizing (2.5rem width) across all states
- Support both light and dark mode themes with proper red color scheme

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Replace confusing MicOff icon with Square icon for stop recording
- Fix recording timer vertical alignment with action buttons
- Move recording indicator inside button group for better layout
- Add smooth hover effects to transcript/summary tabs
- Implement tab-like appearance with rounded top corners
- Add subtle blue background and border hints on tab hover
- Improve overall controls container alignment and spacing

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Implement pause/resume recording functionality with MediaRecorder API
- Add professional HTML5 audio player with timeline scrubbing and volume control
- Enable manual control over when to process recorded audio (no auto-processing)
- Add discard recording option for better user control
- Improve button state management for different recording phases:
  * Default: [Mic] [Upload] [Process Audio]
  * Recording: [Pause] [Stop] [Process Audio]
  * Preview: [Trash] [Upload] [Process Audio] + Audio Player
- Add visual feedback for paused recording state (orange dot, timer shows "(Paused)")
- Style audio player to match app theme with custom controls
- Handle proper cleanup of audio URLs to prevent memory leaks

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Refactored Dockerfile to use multi-stage build with nginx
- Added nginx.conf with production-ready configuration including gzip, security headers, and API proxying
- Updated docker-compose.yml port mapping from 3000:3000 to 80:80
- Removed unnecessary volume mounts for frontend container
- This addresses HTTPS requirements for getUserMedia API and improves production deployment

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove invalid 'must-revalidate' value from gzip_proxied directive
- Change frontend port mapping from 80:80 to 3000:80
- Comment out GPU deployment configuration

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add audio player that displays when file is uploaded
- Allow users to preview uploaded audio before processing
- Add discard functionality for uploaded files
- Integrate same audio controls as recording feature
- Auto-clear uploaded file after processing
- Update button states to handle upload workflow

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Replace emoji trash icon with Trash2 React icon component
- Change button style from btn-danger to btn-discrete for consistency
- Add tooltip for better user experience
- Use btn-icon class for consistent icon styling
- Match visual style of other action buttons (mic, upload)

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Automatically select meeting after successful audio processing
- Set selectedMeetingId in both uploadFile and processAudio functions
- Ensures transcript appears immediately without manual selection
- Improves user experience by eliminating extra click step

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add pollJobStatus function to handle asynchronous job processing
- Replace synchronous processing assumption with proper status checking
- Handle backend responses that return 200 but indicate errors
- Add user-friendly error messages for failed processing
- Implement timeout protection (60 seconds max polling)
- Support both immediate transcript and job polling workflows
- Auto-select processed meeting when job completes successfully

Fixes issue where loading bar didn't properly wait for job completion
and backend errors weren't properly detected despite 200 HTTP status.

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add separate location block for /jobs/ to handle sub-paths
- Fix routing for endpoints like /jobs/{uuid}/status and /jobs/{uuid}/transcript
- Maintain existing /jobs endpoint for job creation
- Ensure proper proxy_pass URLs for both patterns
- Add CORS handling for all job-related endpoints

Previously only /jobs was routed to backend, causing 404s for
status polling and other job management endpoints.

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add \!important declarations to meeting button styles (.btn-past-1 through .btn-past-4)
- Override both background-color and background properties to prevent base .btn interference
- Force white text color with \!important for proper contrast
- Update hover states with consistent darker shades
- Apply fixes to both light and dark mode variants

Previously meeting buttons were invisible in light mode due to CSS
inheritance conflicts between base .btn styles and specific button colors.

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add dark mode specific hover styling for model select dropdown
- Change hover border color from blue to gold (#bba88e) in dark mode
- Update focus state to match gold theme in dark mode
- Maintain blue hover in light mode for consistency

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

Co-Authored-By: Claude <noreply@anthropic.com>
… items

- Increase CSS specificity by using .btn.btn-past-X selectors
- Add \!important to color property in hover states
- Override base .btn hover styles that were making buttons invisible
- Ensure white text color is maintained in all states
- Fix issue where non-selected meeting items weren't visible in light mode

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Increase text truncation limit from 20 to 35 characters
- Expand button width from 15vw to 22vw for more text space
- Add max-width (280px) and min-width (180px) for better responsiveness
- Allow meeting names to display more characters before truncation
- Improve readability of meeting titles in sidebar

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Change meeting button colors from simple 1-2-3-4 repeat pattern
- Implement gradient pattern: 1-2-3-4-3-2-1-2-3-4-3-2...
- Creates smooth visual flow from light to dark and back
- Improves visual hierarchy and aesthetic appeal in meetings list
- Pattern repeats every 6 buttons for consistent gradient effect

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove public /logs endpoint from backend API for security
- Add PYTHONUNBUFFERED=1 to Docker backend service to fix log buffering
- Backend logs will now appear properly in docker logs output

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

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

Summary of Changes

Hello @NotYuSheng, 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!

I've focused on significantly enhancing the user interface and overall application infrastructure. While the primary visual goal was to implement a gradient color pattern for meeting buttons to improve aesthetic hierarchy, this pull request also includes a substantial refactor of the frontend serving architecture and improvements to the audio recording and upload experience.

Highlights

  • Comprehensive UI/UX Overhaul: I've implemented a comprehensive visual refresh across the application, focusing on a new gradient color pattern for meeting buttons to enhance visual hierarchy. This involved extensive updates to CSS variables, introducing smooth gradients for backgrounds, borders, and all button types, along with new discrete button styles and refined shadow effects for a more modern and cohesive user interface.
  • Frontend Infrastructure Migration to Nginx: I've refactored the frontend serving mechanism, migrating from a direct development server to a production-ready Nginx setup within Docker. This significant infrastructure change includes a new multi-stage Dockerfile and a dedicated nginx.conf to efficiently serve static React assets, manage client-side routing, optimize caching, and proxy API requests to the backend.
  • Enhanced Audio Recording & Upload Workflow: I've enhanced the audio recording and upload workflow by adding new functionalities such as the ability to pause and resume recordings, display real-time audio previews for both recorded and uploaded files, and options to discard audio. The processing flow now includes robust polling for job status, ensuring a smoother experience for longer transcription tasks.
  • Dependency Updates & Minor Backend Adjustments: I've updated the react-router-dom dependency to its latest version. On the backend, I removed an unused /logs endpoint and added PYTHONUNBUFFERED to the Docker environment for Python, along with commenting out GPU deployment resources in docker-compose.yml.
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.

Copy link
Copy Markdown
Contributor

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

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 significant number of changes beyond the described UI enhancement for meeting buttons. It includes a major UI overhaul, a move to a production-ready multi-stage Docker build with Nginx for the frontend, and a shift to asynchronous job processing on the backend with polling from the frontend. While these are excellent improvements, the PR description should be updated to reflect the full scope of these changes to ensure reviewers and future developers understand the context. My review covers some potential improvements and concerns in these new additions.

Comment thread docker-compose.yml
Comment on lines +22 to +28
# deploy:
# resources:
# reservations:
# devices:
# - driver: nvidia
# count: all
# capabilities: [gpu]
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.

critical

The deploy configuration for GPU resources has been commented out. If the Whisper model transcription relies on a GPU for performance, this change could significantly degrade performance or even cause the application to fail on large files if it runs out of memory on CPU. Please clarify if this change is intentional and if GPU support is no longer required. If it is, the documentation should be updated to reflect this.

Comment thread frontend/nginx.conf

# Handle preflight requests for CORS
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
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

Using a wildcard * for Access-Control-Allow-Origin is overly permissive and can pose a security risk, especially in a production environment. It's recommended to restrict this to the specific origin(s) that are supposed to access this API. For example, you could use $http_origin and a map to whitelist allowed origins. This concern also applies to line 70.

Comment on lines +387 to +418
const pollJobStatus = async (uuid, maxAttempts = 30) => {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
try {
const response = await fetch(`${API_BASE_URL}/jobs/${uuid}/status`);
const statusData = await response.json();

if (statusData.status === 'completed') {
// Job completed, fetch transcript
const transcriptResponse = await fetch(`${API_BASE_URL}/jobs/${uuid}/transcript`);
const transcriptData = await transcriptResponse.json();

if (transcriptData.full_transcript) {
const parsed = JSON.parse(transcriptData.full_transcript || "[]");
setTranscript(processTranscriptWithSpeakerIds(parsed));
setSelectedMeetingId(uuid);
fetchSummary(uuid);
fetchMeetingList();
return true;
}
} else if (statusData.status === 'failed' || statusData.status === 'error') {
throw new Error(statusData.error_message || 'Job failed');
}

// Job still processing, wait and retry
await new Promise(resolve => setTimeout(resolve, 2000));
} catch (error) {
console.error('Error polling job status:', error);
throw error;
}
}
throw new Error('Job polling timeout - processing took too long');
};
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 pollJobStatus function polls for a maximum of 60 seconds (30 attempts * 2 seconds). This might not be sufficient for transcribing long audio files, which could lead to a timeout on the frontend even if the job succeeds on the backend. It would be more robust to make the timeout longer, or perhaps implement a more sophisticated notification system like WebSockets instead of polling.

Comment thread frontend/nginx.conf
Comment on lines +41 to +78
location /jobs/ {
proxy_pass http://backend:8000/jobs/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# Handle preflight requests for CORS
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE, PATCH';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
}

# Also handle exact /jobs endpoint (without trailing slash)
location /jobs {
proxy_pass http://backend:8000/jobs;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# Handle preflight requests for CORS
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE, PATCH';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
}
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 configuration for /jobs/ and /jobs location blocks is almost identical, including the CORS preflight handling. This duplication can be a maintenance issue. You could consolidate these into a single block using a regular expression to match both paths, for example location ~ ^/jobs/?$ { ... }. This would make the configuration cleaner and easier to maintain.

Comment on lines +695 to 699
.btn.btn-past-1 {
background-color: #2998d5 !important;
background: #2998d5 !important;
color: #fff !important;
}
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 use of !important is generally discouraged as it can lead to CSS that is difficult to maintain and debug. The new button styles can likely be applied by increasing selector specificity instead. For example, the .btn.btn-past-1 selector already has higher specificity than just .btn. You should be able to remove !important from this rule and others like it in this file.

background-color: #2998d5;
color: #fff;
.btn.btn-past-1 {
background-color: #2998d5 !important;
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 background-color property on this line is redundant because the background shorthand property is set on the next line and will override it. You can safely remove this line. This applies to all .btn-past-* rules in this file.

Comment on lines +46 to +49
// eslint-disable-next-line no-unused-vars
const [isPlayingRecording, setIsPlayingRecording] = useState(false);
// eslint-disable-next-line no-unused-vars
const [isPlayingUpload, setIsPlayingUpload] = useState(false);
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 state variables isPlayingRecording and isPlayingUpload are set but never read. This suggests that the feature to visually indicate that audio is playing is incomplete. You should either use these state variables to provide feedback to the user (e.g., changing an icon or showing an indicator) or remove them if they are not needed.

setSelectedFile(null);
} catch (err) {
console.error("Failed to process uploaded file:", err);
alert(`Failed to process file: ${err.message}`);
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

Using alert() for error handling provides a poor user experience as it's a blocking and intrusive browser dialog. It would be better to implement a more user-friendly notification system, such as toast messages or an inline error message component, to inform the user about failures during file processing. This also applies to the error handling on line 496.

Comment on lines 761 to +858
<div className="button-group">
<button
onClick={isRecording ? stopRecording : startRecording}
className={`btn ${isRecording ? "btn-danger" : "btn-primary"}`}
>
{isRecording ? (
<MicOff className="btn-icon" />
) : (
<Mic className="btn-icon" />
)}
{isRecording ? "Stop Recording" : "Start Recording"}
</button>
{!isRecording && !recordedAudio && !selectedFile ? (
<>
<button
onClick={startRecording}
className="btn btn-discrete"
title="Start Recording"
>
<Mic className="btn-icon" />
</button>

<button
onClick={() => fileInputRef.current?.click()}
className="btn btn-secondary"
>
<Upload className="btn-icon" />
{selectedFile ? "Change Audio File" : "Upload Audio File"}
</button>
<button
onClick={() => fileInputRef.current?.click()}
className="btn btn-discrete"
title="Upload Audio File"
>
<Upload className="btn-icon" />
</button>
</>
) : isRecording ? (
<>
<button
onClick={isPaused ? resumeRecording : pauseRecording}
className="btn btn-discrete"
title={isPaused ? "Resume Recording" : "Pause Recording"}
>
{isPaused ? (
<Play className="btn-icon" />
) : (
<Pause className="btn-icon" />
)}
</button>

<button
onClick={stopRecording}
className="btn btn-discrete"
title="Stop Recording"
>
<Square className="btn-icon" />
</button>
</>
) : recordedAudio ? (
<>
<button
onClick={discardRecording}
className="btn btn-discrete"
title="Discard Recording"
>
<Trash2 className="btn-icon" />
</button>

<button
onClick={() => fileInputRef.current?.click()}
className="btn btn-discrete"
title="Upload Audio File"
>
<Upload className="btn-icon" />
</button>
</>
) : selectedFile ? (
<>
<button
onClick={discardUpload}
className="btn btn-discrete"
title="Discard Upload"
>
<Trash2 className="btn-icon" />
</button>

<button
onClick={startRecording}
className="btn btn-discrete"
title="Start Recording"
>
<Mic className="btn-icon" />
</button>
</>
) : null}

<button
onClick={uploadFile}
disabled={!selectedFile || loading}
className={`btn ${selectedFile ? "btn-primary" : "btn-disabled"}`}
onClick={recordedAudio ? processRecordedAudio : uploadFile}
disabled={(!selectedFile && !recordedAudio) || loading}
className={`btn ${(selectedFile || recordedAudio) && !loading ? "btn-discrete-prominent" : "btn-discrete"}`}
title={loading ? "Processing..." : "Process Audio"}
>
<Send className="btn-icon" />
{loading ? "Transcribing..." : "Start Transcription"}
{((selectedFile || recordedAudio) && !loading) ? "Process Audio" : ""}
</button>
</div>

{isRecording && (
<div className="recording-indicator">
<div className="recording-dot"></div>
<span className="recording-time">
{formatTime(recordingTime)}
</span>
</div>
)}
{isRecording && (
<div className="recording-indicator">
<div className={`recording-dot ${isPaused ? 'paused' : ''}`}></div>
<span className="recording-time">
{formatTime(recordingTime)} {isPaused ? '(Paused)' : ''}
</span>
</div>
)}
</div>
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 logic to render the action buttons has become quite complex with multiple nested ternary operators. This can be difficult to read and maintain. Consider refactoring this logic into a separate component or a helper function that returns the correct set of buttons based on the application's state (isRecording, isPaused, recordedAudio, selectedFile). This would improve readability and make the main component's render method cleaner.

@NotYuSheng NotYuSheng merged commit ebe0143 into main Aug 7, 2025
0 of 4 checks passed
@NotYuSheng NotYuSheng deleted the ui/meeting-buttons-gradient-color-pattern branch August 7, 2025 02:41
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