|
666 | 666 | font-style: italic; |
667 | 667 | } |
668 | 668 |
|
| 669 | + /* === Calendar all-day strip — pinned to top of panel === */ |
| 670 | + .cal-allday { |
| 671 | + display: flex; |
| 672 | + align-items: baseline; |
| 673 | + gap: 14px; |
| 674 | + padding: 5px 12px 5px 10px; |
| 675 | + margin-bottom: 10px; |
| 676 | + background: rgba(160, 56, 46, 0.05); |
| 677 | + border-left: 2px solid var(--stamp); |
| 678 | + overflow: hidden; |
| 679 | + } |
| 680 | + .cal-allday-label { |
| 681 | + font-family: 'Noto Serif TC', serif; |
| 682 | + font-size: 10px; |
| 683 | + letter-spacing: 0.4em; |
| 684 | + color: var(--stamp); |
| 685 | + flex-shrink: 0; |
| 686 | + font-weight: 500; |
| 687 | + } |
| 688 | + .cal-allday-list { |
| 689 | + font-family: 'Noto Serif TC', serif; |
| 690 | + font-size: 12px; |
| 691 | + color: var(--ink); |
| 692 | + letter-spacing: 0.05em; |
| 693 | + white-space: nowrap; |
| 694 | + overflow: hidden; |
| 695 | + text-overflow: ellipsis; |
| 696 | + min-width: 0; |
| 697 | + flex: 1; |
| 698 | + } |
| 699 | + .cal-allday-tmr { |
| 700 | + color: var(--ink-faint); |
| 701 | + font-style: italic; |
| 702 | + margin-right: 6px; |
| 703 | + font-size: 10px; |
| 704 | + } |
| 705 | + |
669 | 706 | /* === Calendar === */ |
670 | 707 | .cal-now { |
671 | 708 | background: var(--bg-deep); |
|
1534 | 1571 | // ================================================================= |
1535 | 1572 | function CalendarPanel({ data }) { |
1536 | 1573 | const CAL_EVENTS = data?.calendar?.events || []; |
1537 | | - const todayEvents = CAL_EVENTS.filter(e => e.day === 'today'); |
1538 | | - const tomorrowEvents = CAL_EVENTS.filter(e => e.day === 'tomorrow'); |
1539 | | - // Events without a `day` tag (fallback demo data) → treated as today. |
1540 | | - const undatedEvents = CAL_EVENTS.filter(e => !e.day); |
| 1574 | + |
| 1575 | + // Pull all-day events out — they live in their own strip, never in 即將. |
| 1576 | + const allDayEvents = CAL_EVENTS.filter(e => e.isAllDay); |
| 1577 | + const timedEvents = CAL_EVENTS.filter(e => !e.isAllDay); |
| 1578 | + |
| 1579 | + const todayEvents = timedEvents.filter(e => e.day === 'today'); |
| 1580 | + const tomorrowEvents = timedEvents.filter(e => e.day === 'tomorrow'); |
| 1581 | + const undatedEvents = timedEvents.filter(e => !e.day); |
1541 | 1582 | const todayLike = todayEvents.length ? todayEvents : undatedEvents; |
1542 | 1583 |
|
1543 | | - // Featured "即將" — today's next event; if none, tomorrow's first. |
1544 | 1584 | const next = todayLike[0] || tomorrowEvents[0]; |
1545 | 1585 | const isTomorrow = !todayLike.length && !!tomorrowEvents.length; |
1546 | | - // List below — rest of the same day as the featured event. |
1547 | 1586 | const rest = isTomorrow ? tomorrowEvents.slice(1) : todayLike.slice(1); |
1548 | 1587 |
|
1549 | 1588 | const headerCount = todayLike.length || tomorrowEvents.length; |
1550 | 1589 | const headerLabel = isTomorrow |
1551 | | - ? `Tomorrow · ${headerCount} event${headerCount === 1 ? '' : 's'}` |
1552 | | - : `Today · ${headerCount} event${headerCount === 1 ? '' : 's'}`; |
| 1590 | + ? `Tomorrow · ${headerCount} timed event${headerCount === 1 ? '' : 's'}` |
| 1591 | + : `Today · ${headerCount} timed event${headerCount === 1 ? '' : 's'}`; |
1553 | 1592 |
|
1554 | 1593 | return ( |
1555 | 1594 | <div className="tab-panel-inner"> |
1556 | 1595 | <div className="panel-head"> |
1557 | 1596 | <span className="panel-title">行 事 曆</span> |
1558 | 1597 | <span className="panel-title-en">{headerLabel}</span> |
1559 | 1598 | </div> |
| 1599 | + {allDayEvents.length > 0 && ( |
| 1600 | + <div className="cal-allday" title={allDayEvents.map(e => e.name).join(' · ')}> |
| 1601 | + <span className="cal-allday-label">全 日</span> |
| 1602 | + <span className="cal-allday-list"> |
| 1603 | + {allDayEvents.map((e, i) => ( |
| 1604 | + <React.Fragment key={i}> |
| 1605 | + {i > 0 && <span style={{color: 'var(--ink-faint)', margin: '0 6px'}}>·</span>} |
| 1606 | + {e.day === 'tomorrow' && <span className="cal-allday-tmr">明日</span>} |
| 1607 | + {e.name} |
| 1608 | + </React.Fragment> |
| 1609 | + ))} |
| 1610 | + </span> |
| 1611 | + </div> |
| 1612 | + )} |
1560 | 1613 | {next ? ( |
1561 | 1614 | <div className={`cal-now ${isTomorrow ? 'is-tomorrow' : ''}`}> |
1562 | 1615 | <div> |
|
1577 | 1630 | )} |
1578 | 1631 | </div> |
1579 | 1632 | </div> |
1580 | | - ) : ( |
| 1633 | + ) : allDayEvents.length === 0 ? ( |
1581 | 1634 | <div className="cal-now"> |
1582 | 1635 | <div> |
1583 | 1636 | <div className="cal-event-title">最近沒有行程</div> |
1584 | 1637 | <div className="cal-event-meta">enjoy a slow day · ☕</div> |
1585 | 1638 | </div> |
1586 | 1639 | </div> |
1587 | | - )} |
| 1640 | + ) : null} |
1588 | 1641 | <div className="cal-list"> |
1589 | 1642 | {rest.map((e, i) => ( |
1590 | 1643 | <div className="cal-row" key={i}> |
|
0 commit comments