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

@sean-brydon sean-brydon deleted the devin/dynamic-overlap-offsets-1763722743 branch November 24, 2025 12:01
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