Skip to content

Commit

Permalink
ref(replay): Extract useTimelineScale from useReplayContext and tweak…
Browse files Browse the repository at this point in the history
… ui styles (#73613)

The UI tweaks come from this older figma:
https://www.figma.com/design/tlGOyIijfu309du7zXTDTM/Library%3A-Replay?node-id=0-1&t=iRFVZSPdf7cuccpS-0

Changes:
- Down Triangle for both sides
- Triangle is a little higher, so it's not cutoff by the scrubber circle
when they point to the same spot (see image below)
- Unicode `x`
- font size/weight/color changes for the current/total time labels

**After:**
<img width="704" alt="SCR-20240701-oerr"
src="https://github.com/getsentry/sentry/assets/187460/3f5152d2-bf75-468e-9cfc-a498a3aed0d1">
  • Loading branch information
ryan953 authored Jul 3, 2024
1 parent cadd0a4 commit c2cb053
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 55 deletions.
4 changes: 3 additions & 1 deletion static/app/components/replays/breadcrumbs/replayTimeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ import {useTimelineScrubberMouseTracking} from 'sentry/components/replays/player
import {useReplayContext} from 'sentry/components/replays/replayContext';
import divide from 'sentry/utils/number/divide';
import toPercent from 'sentry/utils/number/toPercent';
import useTimelineScale from 'sentry/utils/replays/hooks/useTimelineScale';
import {useDimensions} from 'sentry/utils/useDimensions';

export default function ReplayTimeline() {
const {replay, currentTime, timelineScale} = useReplayContext();
const {replay, currentTime} = useReplayContext();
const [timelineScale] = useTimelineScale();

const panelRef = useRef<HTMLDivElement>(null);
const mouseTrackingProps = useTimelineScrubberMouseTracking(
Expand Down
22 changes: 8 additions & 14 deletions static/app/components/replays/player/scrubber.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ import {space} from 'sentry/styles/space';
import formatReplayDuration from 'sentry/utils/duration/formatReplayDuration';
import divide from 'sentry/utils/number/divide';
import toPercent from 'sentry/utils/number/toPercent';
import useTimelineScale from 'sentry/utils/replays/hooks/useTimelineScale';

type Props = {
className?: string;
showZoomIndicators?: boolean;
};

function Scrubber({className, showZoomIndicators = false}: Props) {
const {replay, currentHoverTime, currentTime, setCurrentTime, timelineScale} =
useReplayContext();
const {replay, currentHoverTime, currentTime, setCurrentTime} = useReplayContext();
const [timelineScale] = useTimelineScale();

const durationMs = replay?.getDurationMs() ?? 0;
const percentComplete = divide(currentTime, durationMs);
Expand All @@ -44,15 +45,15 @@ function Scrubber({className, showZoomIndicators = false}: Props) {
<Wrapper className={className}>
{showZoomIndicators ? (
<Fragment>
<ZoomIndicatorContainer style={{left: toPercent(translate()), top: '-10px'}}>
<ZoomIndicatorContainer style={{left: toPercent(translate())}}>
<ZoomTriangleDown />
<ZoomIndicator />
</ZoomIndicatorContainer>
<ZoomIndicatorContainer
style={{left: toPercent(translate() + 2 * initialTranslate), top: '-2px'}}
style={{left: toPercent(translate() + 2 * initialTranslate)}}
>
<ZoomTriangleDown />
<ZoomIndicator />
<ZoomTriangleUp />
</ZoomIndicatorContainer>
</Fragment>
) : null}
Expand Down Expand Up @@ -140,8 +141,9 @@ const ZoomIndicatorContainer = styled('div')`
display: flex;
flex-direction: column;
align-items: center;
gap: ${space(0.5)};
gap: ${space(0.75)};
translate: -6px;
top: -12px;
`;

const ZoomIndicator = styled('div')`
Expand All @@ -158,14 +160,6 @@ const ZoomTriangleDown = styled('div')`
border-top: 4px solid ${p => p.theme.gray500};
`;

const ZoomTriangleUp = styled('div')`
width: 0;
height: 0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-bottom: 4px solid ${p => p.theme.gray500};
`;

export const TimelineScrubber = styled(Scrubber)`
height: 100%;
Expand Down
15 changes: 0 additions & 15 deletions static/app/components/replays/replayContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,21 +138,11 @@ interface ReplayPlayerContextProps extends HighlightCallbacks {
*/
setSpeed: (speed: number) => void;

/**
* Set the timeline width to the specific scale, starting at 1x and growing larger
*/
setTimelineScale: (size: number) => void;

/**
* The speed for normal playback
*/
speed: number;

/**
* Scale of the timeline width, starts from 1x and increases by 1x
*/
timelineScale: number;

/**
* Start or stop playback
*
Expand Down Expand Up @@ -189,9 +179,7 @@ const ReplayPlayerContext = createContext<ReplayPlayerContextProps>({
setCurrentTime: () => {},
setRoot: () => {},
setSpeed: () => {},
setTimelineScale: () => {},
speed: 1,
timelineScale: 1,
togglePlayPause: () => {},
toggleSkipInactive: () => {},
});
Expand Down Expand Up @@ -275,7 +263,6 @@ export function Provider({
const [isVideoBuffering, setVideoBuffering] = useState(false);
const playTimer = useRef<number | undefined>(undefined);
const didApplyInitialOffset = useRef(false);
const [timelineScale, setTimelineScale] = useState(1);
const [rootEl, setRoot] = useState<HTMLDivElement | null>(null);

const durationMs = replay?.getDurationMs() ?? 0;
Expand Down Expand Up @@ -721,9 +708,7 @@ export function Provider({
setCurrentHoverTime,
setCurrentTime,
setSpeed,
setTimelineScale,
speed,
timelineScale,
togglePlayPause,
toggleSkipInactive,
...value,
Expand Down
58 changes: 33 additions & 25 deletions static/app/components/replays/timeAndScrubberGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,23 @@ import {IconAdd, IconSubtract} from 'sentry/icons';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import formatReplayDuration from 'sentry/utils/duration/formatReplayDuration';
import useTimelineScale, {
TimelineScaleContextProvider,
} from 'sentry/utils/replays/hooks/useTimelineScale';

type TimeAndScrubberGridProps = {
isCompact?: boolean;
showZoom?: boolean;
};

function TimelineSizeBar() {
const {replay, timelineScale, setTimelineScale} = useReplayContext();
const {replay} = useReplayContext();
const [timelineScale, setTimelineScale] = useTimelineScale();
const durationMs = replay?.getDurationMs();
const maxScale = durationMs ? Math.ceil(durationMs / 60000) : 10;

return (
<ButtonBar>
<ButtonBar gap={0.5}>
<Button
size="xs"
title={t('Zoom out')}
Expand All @@ -33,10 +37,10 @@ function TimelineSizeBar() {
aria-label={t('Zoom out')}
disabled={timelineScale === 1}
/>
<span style={{padding: `0 ${space(0.5)}`}}>
<Numeric>
{timelineScale}
{t('x')}
</span>
{'\u00D7'}
</Numeric>
<Button
size="xs"
title={t('Zoom in')}
Expand All @@ -50,7 +54,7 @@ function TimelineSizeBar() {
);
}

function TimeAndScrubberGrid({
export default function TimeAndScrubberGrid({
isCompact = false,
showZoom = false,
}: TimeAndScrubberGridProps) {
Expand All @@ -60,21 +64,25 @@ function TimeAndScrubberGrid({
const mouseTrackingProps = useScrubberMouseTracking({elem});

return (
<Grid id="replay-timeline-player" isCompact={isCompact}>
<Time style={{gridArea: 'currentTime'}}>{formatReplayDuration(currentTime)}</Time>
<div style={{gridArea: 'timeline'}}>
<ReplayTimeline />
</div>
<div style={{gridArea: 'timelineSize', fontVariantNumeric: 'tabular-nums'}}>
{showZoom ? <TimelineSizeBar /> : null}
</div>
<StyledScrubber style={{gridArea: 'scrubber'}} ref={elem} {...mouseTrackingProps}>
<PlayerScrubber showZoomIndicators={showZoom} />
</StyledScrubber>
<Time style={{gridArea: 'duration'}}>
{durationMs ? formatReplayDuration(durationMs) : '--:--'}
</Time>
</Grid>
<TimelineScaleContextProvider>
<Grid id="replay-timeline-player" isCompact={isCompact}>
<Numeric style={{gridArea: 'currentTime', paddingInline: space(1.5)}}>
{formatReplayDuration(currentTime)}
</Numeric>
<div style={{gridArea: 'timeline'}}>
<ReplayTimeline />
</div>
<div style={{gridArea: 'timelineSize', fontVariantNumeric: 'tabular-nums'}}>
{showZoom ? <TimelineSizeBar /> : null}
</div>
<StyledScrubber style={{gridArea: 'scrubber'}} ref={elem} {...mouseTrackingProps}>
<PlayerScrubber showZoomIndicators={showZoom} />
</StyledScrubber>
<Numeric style={{gridArea: 'duration', paddingInline: space(1.5)}}>
{durationMs ? formatReplayDuration(durationMs) : '--:--'}
</Numeric>
</Grid>
</TimelineScaleContextProvider>
);
}

Expand Down Expand Up @@ -103,9 +111,9 @@ const StyledScrubber = styled('div')`
align-items: center;
`;

const Time = styled('span')`
const Numeric = styled('span')`
color: ${p => p.theme.gray300};
font-size: ${p => p.theme.fontSizeSmall};
font-variant-numeric: tabular-nums;
padding: 0 ${space(1.5)};
font-weight: ${p => p.theme.fontWeightBold};
`;

export default TimeAndScrubberGrid;
16 changes: 16 additions & 0 deletions static/app/utils/replays/hooks/useTimelineScale.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {createContext, useContext, useState} from 'react';

const context = createContext<[scale: number, setScale: (scale: number) => void]>([
1,
(_scale: number) => {},
]);

export function TimelineScaleContextProvider({children}: {children: React.ReactNode}) {
const state = useState(1);

return <context.Provider value={state}>{children}</context.Provider>;
}

export default function useTimelineScale() {
return useContext(context);
}

0 comments on commit c2cb053

Please sign in to comment.