Skip to content

Sprint/3#4

Merged
kooksee merged 5 commits into
masterfrom
sprint/3
Jun 27, 2026
Merged

Sprint/3#4
kooksee merged 5 commits into
masterfrom
sprint/3

Conversation

@kooksee

@kooksee kooksee commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

kooksee added 5 commits May 11, 2026 11:17
- Introduced a new CSS theme for slides presentation in `theme-markview.css`.
- Implemented `MarkdownViewer` tests to verify slides mode functionality, including page flipping and keyboard navigation.
- Created `SlidesToggle` component to manage the visibility of slides, with corresponding tests to ensure correct behavior and accessibility attributes.
@kooksee kooksee merged commit d157d55 into master Jun 27, 2026
1 of 3 checks passed

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

Copy link
Copy Markdown

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 new built-in Slides presentation mode for Markdown files, featuring slide navigation, full-screen capabilities, and auto-hiding overlay controls. It also adds Marp slide templates, Makefile targets for slide preview/export, and a safe pnpm installation script to handle architecture switches. The review feedback focuses on refining the React implementation: typing the overlay timer reference to prevent TypeScript compilation issues, throttling mouse movement events to optimize performance, preventing slide progression during text selection, and preserving keyboard accessibility for interactive elements on slides.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +1840 to +1841
const slideShellRef = useRef<HTMLDivElement>(null);
const slidesOverlayTimerRef = useRef<number | null>(null);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

To avoid potential TypeScript compilation errors in environments where Node.js types are loaded globally (where setTimeout returns a Timeout object instead of a number), it is highly recommended to type the slidesOverlayTimerRef using ReturnType<typeof setTimeout>. Additionally, we can introduce a lastOverlayResetRef to throttle overlay visibility timer resets during continuous mouse movement.

Suggested change
const slideShellRef = useRef<HTMLDivElement>(null);
const slidesOverlayTimerRef = useRef<number | null>(null);
const slideShellRef = useRef<HTMLDivElement>(null);
const slidesOverlayTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const lastOverlayResetRef = useRef<number>(0);

Comment on lines +2136 to +2138
const handleSlidesOverlayActivity = useCallback(() => {
revealSlidesOverlay();
}, [revealSlidesOverlay]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The onMouseMove event fires extremely frequently (dozens of times per second). Resetting the overlay timer on every single mouse movement by clearing and setting timeouts can cause performance stuttering, especially on lower-end devices. Throttling the timer resets to at most once every 200ms significantly reduces CPU overhead while maintaining the same user experience.

  const handleSlidesOverlayActivity = useCallback(() => {
    const now = Date.now();
    if (now - lastOverlayResetRef.current > 200) {
      lastOverlayResetRef.current = now;
      revealSlidesOverlay();
    }
  }, [revealSlidesOverlay]);

Comment on lines +2053 to +2063
const handleSlidePageClick = useCallback(
(event: React.MouseEvent<HTMLElement>) => {
const target = event.target as HTMLElement | null;
if (!target) return;
if (target.closest("a,button,input,textarea,select,label,summary,[role='button']")) {
return;
}
goNextSlide();
},
[goNextSlide],
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

When a user attempts to select and copy text from a slide, clicking and dragging or double-clicking will trigger the slide click handler and unexpectedly advance to the next slide. Checking if there is active text selection via window.getSelection() before advancing prevents this frustrating user experience.

  const handleSlidePageClick = useCallback(
    (event: React.MouseEvent<HTMLElement>) => {
      const target = event.target as HTMLElement | null;
      if (!target) return;
      if (target.closest("a,button,input,textarea,select,label,summary,[role='button']")) {
        return;
      }
      // Avoid advancing slides when user is selecting text
      if (window.getSelection()?.toString()) {
        return;
      }
      goNextSlide();
    },
    [goNextSlide],
  );

Comment on lines +2335 to +2355
const onKeyDown = (event: KeyboardEvent) => {
const target = event.target as HTMLElement | null;
if (
target &&
(target.tagName === "INPUT" ||
target.tagName === "TEXTAREA" ||
target.tagName === "SELECT" ||
target.isContentEditable)
) {
return;
}

if (isSlidesFullscreen) {
revealSlidesOverlay();
}

if (["ArrowRight", "PageDown", " ", "Enter"].includes(event.key)) {
event.preventDefault();
goNextSlide();
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

When keyboard focus is on an interactive element (such as a button, link, or summary) within the slide, pressing Space or Enter should activate that element rather than navigating to the next slide. Intercepting these keys globally breaks standard keyboard accessibility (a11y). We should bypass slide navigation for Space and Enter when focusing interactive elements.

    const onKeyDown = (event: KeyboardEvent) => {
      const target = event.target as HTMLElement | null;
      if (
        target &&
        (target.tagName === "INPUT" ||
          target.tagName === "TEXTAREA" ||
          target.tagName === "SELECT" ||
          target.isContentEditable)
      ) {
        return;
      }

      // Avoid intercepting Space/Enter when focusing interactive elements
      const isInteractive = target && (
        target.tagName === "BUTTON" ||
        target.tagName === "A" ||
        target.tagName === "SUMMARY" ||
        target.getAttribute("role") === "button"
      );
      if (isInteractive && (event.key === " " || event.key === "Enter")) {
        return;
      }

      if (isSlidesFullscreen) {
        revealSlidesOverlay();
      }

      if (["ArrowRight", "PageDown", " ", "Enter"].includes(event.key)) {
        event.preventDefault();
        goNextSlide();
        return;
      }

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