Skip to content

Conversation

@eunjae-lee
Copy link
Contributor

@eunjae-lee eunjae-lee commented Nov 21, 2025

What does this PR do?

Improves the visual presentation of overlapping calendar events in the weekly view with two key enhancements:

  • Dynamic startHour per scenario: Each playground scenario now displays the calendar starting at an appropriate hour based
    on its earliest event time, rather than always starting at 6am
  • Full width for non-overlapping events: Single events and non-overlapping events now display at 100% width (previously
    80%) for maximum visibility

Key Changes

Overlapping Event Layout Algorithm

Replaces the previous uniform-width, fixed-offset layout with an intelligent spread algorithm:

Previous behavior:

  • All overlapping events: 80% width with 8% offset steps
  • Events clustered on the left side

New behavior:

  • 2 overlapping events: 80% and 50% widths
  • 3 overlapping events: 55%, ~42%, and 33% widths
  • 4+ overlapping events: Progressive narrowing from 40% down to minimum 25%
  • Spread algorithm: Events distribute across the full width with the last event aligned to the right edge
  • Right edge distribution: ri = Rmin + (Rmax - Rmin) × i/(n-1) for even spacing

Visual Improvements

  • Single/non-overlapping events: 100% width (was 80%)
  • Overlapping events: Variable widths based on cascade position (leftmost events wider, rightmost narrower)
  • Last overlapping event: Aligned to right border for maximum scatter
  • Minimum width: 25% maintained for readability

Devin session: https://app.devin.ai/sessions/168d2227f5304c49ae4d34d17da5b025
Requested by: [email protected] (@eunjae-lee)

Visual Demo

Screenshot.2025-11-24.at.10.30.55.mp4

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. N/A - playground-only changes
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  1. Navigate to /settings/admin/playground/weekly-calendar
  2. Verify each scenario:
    • Non-Overlapping Events: Both events should be 100% width, no offset
    • Touching Events: Both events should be 100% width, no offset
    • Two Overlapping Events: First event 80% width, second 50% width aligned to right
    • Three Overlapping Events: Progressive narrowing with spread across full width
    • Four Overlapping Events: Four events spread across full width
  3. Verify startHour values:
    • Most scenarios should start at 9am (events start at 10am)
    • Dense day scenario should start at 8am (events start at 9am)
    • Mixed statuses scenario should start at 1pm (events start at 2pm)
  4. Test with real calendar data to ensure overlapping events look visually distinct

Environment variables: Standard Cal.com development setup
Test data: Use playground scenarios or create overlapping events in your calendar

Human Review Checklist

⚠️ CRITICAL ITEMS:

  1. Visual verification in playground (MOST IMPORTANT):

    • Open /settings/admin/playground/weekly-calendar
    • Verify non-overlapping events are 100% width (not 80%)
    • Verify overlapping events spread properly across full width
    • Verify last overlapping event aligns to right edge
    • Verify each scenario starts at appropriate hour
  2. Algorithm correctness:

    • Single events: 100% width (was 80%)
    • Two overlapping: 80%, 50% widths with last aligned to right
    • Three overlapping: 55%, ~42%, 33% widths spread across full width
    • Right-edge distribution: ri = Rmin + (Rmax - Rmin) * i/(n-1)
  3. Edge cases:

    • Test with 10+ overlapping events to ensure no overflow
    • Verify minimum width (25%) is respected
    • Verify backward compatibility: custom baseWidthPercent/offsetStepPercent should use legacy behavior
  4. Type safety:

    • startHour parameter now properly typed as Hours (union of 0-23)
    • All scenarios use valid Hours values

Known limitations:

  • Local visual testing was not completed due to environment issues
  • Easing curve parameters (curveExponent: 1.3) were chosen based on examples but may need visual tuning
  • No E2E tests for visual appearance (only unit tests for layout calculations)

Checklist

  • I have read the contributing guide
  • My code follows the style guidelines of this project
  • I have commented my code, particularly in hard-to-understand areas
  • I have checked if my changes generate no new warnings

- Implement dynamic offset calculation based on number of overlapping events
  - 2 events: 15% offset (larger for better visual distinction)
  - 3 events: 10% offset (medium)
  - 4 events: 8% offset (base)
  - 5+ events: progressively smaller offsets to prevent overflow

- Implement dynamic width reduction for better visual distinction
  - 2 events: 75% width
  - 3 events: 70% width
  - 4 events: 65% width
  - 5+ events: progressively narrower (min 50%)

- Update playground scenarios to showcase the new behavior
  - Updated expected descriptions for 2, 3, and 4 event scenarios
  - Added new scenario specifically for 4 overlapping events

This makes overlapping events more visually distinguishable, with larger
offsets and narrower widths for fewer events, and tighter packing for
many events to prevent overflow.

Co-Authored-By: [email protected] <[email protected]>
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@keithwillcode keithwillcode added consumer core area: core, team members only labels Nov 21, 2025
- Fix implementation to honor explicitly provided baseWidthPercent and offsetStepPercent
- Only apply dynamic calculations when config values are not explicitly set
- Update test expectations to reflect new dynamic behavior:
  - 2 events: 15% offset, 75% width (was 8% offset, 80% width)
  - 3 events: 10% offset, 70% width (was 8% offset, 80% width)
- Rename test to better reflect dynamic width behavior
- All 21 tests now pass

Co-Authored-By: [email protected] <[email protected]>
@pull-request-size pull-request-size bot added size/L and removed size/M labels Nov 21, 2025
@vercel
Copy link

vercel bot commented Nov 21, 2025

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

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
cal Ignored Ignored Nov 24, 2025 9:55am
cal-eu Ignored Ignored Nov 24, 2025 9:55am

@devin-ai-integration devin-ai-integration bot changed the title feat: improve overlapping events with dynamic offsets and widths feat: dynamic offsets and widths for overlapping calendar events Nov 21, 2025
- Replace uniform widths with variable widths based on cascade position
- Leftmost (longest) events get wider widths, rightmost (shortest) get narrower
- Anchor points: 2 events (80%, 50%), 3 events (55%, ~42%, 33%), 4 events (40%, ~33%, ~28%, 25%)
- Use easing curve (exponent 1.3) for smooth width distribution in 5+ events
- Maintain minimum width of 25% for readability
- Update offset calculation to work with variable widths
- Update tests to reflect new variable width behavior
- Update playground scenarios to document new behavior

Co-Authored-By: [email protected] <[email protected]>
@devin-ai-integration devin-ai-integration bot changed the title feat: dynamic offsets and widths for overlapping calendar events feat: variable widths for overlapping calendar events Nov 21, 2025
…gned to right

- Replace fixed-step offsets with linear right edges distribution
- Events now spread across full width instead of clustering on left
- Last event aligns to right border (100% - safety margin)
- Right edges evenly distributed: ri = Rmin + (Rmax - Rmin) * i/(n-1)
- Maintains backward compatibility: explicit offsetStepPercent uses legacy behavior
- Update tests to reflect new offset values (e.g., 2 events: 0%, 49.5%)
- Update playground descriptions to document spread behavior

Co-Authored-By: [email protected] <[email protected]>
@devin-ai-integration devin-ai-integration bot changed the title feat: variable widths for overlapping calendar events feat: spread overlapping events with variable widths and right alignment Nov 21, 2025
devin-ai-integration bot and others added 3 commits November 21, 2025 17:59
- Update CurrentTime component to accept scrollToCurrentTime prop (default: true)
- Pass scrollToCurrentTime from Calendar.tsx to CurrentTime component
- Set scrollToCurrentTime to false in playground to disable auto-scroll
- Maintains backward compatibility with default value of true

Co-Authored-By: [email protected] <[email protected]>
…ts 100% width

- Update calculateVariableWidths to return 100% width for single events (was 80%)
- Add startHour parameter to getBaseProps function in playground
- Set appropriate startHour for each scenario based on earliest event time:
  - Most scenarios: startHour 9 (events start at 10:00)
  - Dense day & event durations: startHour 8 (events start at 9:00)
  - Mixed statuses: startHour 13 (events start at 14:00)
- Update expected descriptions for non-overlapping events to reflect 100% width
- Update test expectations for single event width (99.5% after safety margin)

Co-Authored-By: [email protected] <[email protected]>
- Import Hours type from weeklyview/types/state
- Change startHour parameter type from number to Hours in getBaseProps
- Change Scenario.startHour type from number to Hours
- Fixes type error: Type 'number' is not assignable to type 'Hours | undefined'

Co-Authored-By: [email protected] <[email protected]>
@devin-ai-integration devin-ai-integration bot changed the title feat: spread overlapping events with variable widths and right alignment feat: dynamic startHour per scenario and 100% width for single events Nov 21, 2025
- Remove safety margin cap for single-event groups (allow true 100% width)
- Keep safety margin for overlapping groups to prevent overflow
- Update test expectations from 99.5% to 100% for single events
- Add test for touching events at exact boundaries with 100% width
- Fixes issue where touching events were displaying at 99.5% instead of 100%

Co-Authored-By: [email protected] <[email protected]>
@eunjae-lee eunjae-lee changed the title feat: dynamic startHour per scenario and 100% width for single events fix: improve overlapping events with dynamic offsets and widths Nov 24, 2025
@eunjae-lee eunjae-lee marked this pull request as ready for review November 24, 2025 09:55
@graphite-app graphite-app bot requested a review from a team November 24, 2025 09:55
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 8 files

@github-actions
Copy link
Contributor

github-actions bot commented Nov 24, 2025

E2E results are ready!

@sean-brydon sean-brydon merged commit 251d29f into main Nov 24, 2025
109 of 115 checks passed
Copy link
Member

Merge activity

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

Labels

consumer core area: core, team members only ready-for-e2e size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants