Skip to content

Commit

Permalink
ComicViewerを良い感じに
Browse files Browse the repository at this point in the history
  • Loading branch information
cp-20 committed Mar 23, 2024
1 parent eb12be4 commit 2178989
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 16 deletions.
24 changes: 14 additions & 10 deletions workspaces/app/src/features/viewer/components/ComicViewerCore.tsx
@@ -1,9 +1,10 @@
import { Suspense, useEffect, useState } from 'react';
import { useInterval, useUpdate } from 'react-use';
import { useUpdate } from 'react-use';
import styled from 'styled-components';

import type { GetEpisodeResponse } from '@wsh-2024/schema/src/api/episodes/GetEpisodeResponse';

import { addUnitIfNeeded } from '../../../lib/css/addUnitIfNeeded';
import { useEpisode } from '../../episode/hooks/useEpisode';

import { ComicViewerPage } from './ComicViewerPage';

Expand Down Expand Up @@ -95,15 +96,12 @@ const _Wrapper = styled.div<{
`;

type Props = {
episodeId: string;
episode: GetEpisodeResponse;
};

const ComicViewerCore: React.FC<Props> = ({ episodeId }) => {
const ComicViewerCore: React.FC<Props> = ({ episode }) => {
// 画面のリサイズに合わせて再描画する
const rerender = useUpdate();
useInterval(rerender, 0);

const { data: episode } = useEpisode({ params: { episodeId } });

const [container, containerRef] = useState<HTMLDivElement | null>(null);
const [scrollView, scrollViewRef] = useState<HTMLDivElement | null>(null);
Expand All @@ -130,6 +128,7 @@ const ComicViewerCore: React.FC<Props> = ({ episodeId }) => {
let scrollToLeftWhenScrollEnd = 0;

const handlePointerDown = (ev: PointerEvent) => {
rerender();
const scrollView = ev.currentTarget as HTMLDivElement;
isPressed = true;
scrollView.style.cursor = 'grabbing';
Expand All @@ -138,6 +137,7 @@ const ComicViewerCore: React.FC<Props> = ({ episodeId }) => {
};

const handlePointerMove = (ev: PointerEvent) => {
rerender();
if (isPressed) {
const scrollView = ev.currentTarget as HTMLDivElement;
scrollView.scrollBy({
Expand All @@ -149,6 +149,7 @@ const ComicViewerCore: React.FC<Props> = ({ episodeId }) => {
};

const handlePointerUp = (ev: PointerEvent) => {
rerender();
const scrollView = ev.currentTarget as HTMLDivElement;
isPressed = false;
scrollView.style.cursor = 'grab';
Expand All @@ -157,6 +158,7 @@ const ComicViewerCore: React.FC<Props> = ({ episodeId }) => {
};

const handleScroll = (ev: Pick<Event, 'currentTarget'>) => {
rerender();
const scrollView = ev.currentTarget as HTMLDivElement;
scrollToLeftWhenScrollEnd = getScrollToLeft({ pageCountParView, pageWidth, scrollView });
};
Expand All @@ -165,6 +167,7 @@ const ComicViewerCore: React.FC<Props> = ({ episodeId }) => {
abortController.signal.addEventListener('abort', () => window.clearTimeout(scrollEndTimer), { once: true });

const handleScrollEnd = (ev: Pick<Event, 'currentTarget'>) => {
rerender();
const scrollView = ev.currentTarget as HTMLDivElement;

// マウスが離されるまではスクロール中とみなす
Expand All @@ -181,6 +184,7 @@ const ComicViewerCore: React.FC<Props> = ({ episodeId }) => {

let prevContentRect: DOMRectReadOnly | null = null;
const handleResize = (entries: ResizeObserverEntry[]) => {
rerender();
if (prevContentRect != null && prevContentRect.width !== entries[0]?.contentRect.width) {
requestAnimationFrame(() => {
scrollView?.scrollBy({
Expand All @@ -205,7 +209,7 @@ const ComicViewerCore: React.FC<Props> = ({ episodeId }) => {
return () => {
abortController.abort();
};
}, [pageCountParView, pageWidth, scrollView]);
}, [pageCountParView, pageWidth, rerender, scrollView]);

return (
<_Container ref={containerRef}>
Expand All @@ -218,10 +222,10 @@ const ComicViewerCore: React.FC<Props> = ({ episodeId }) => {
);
};

const ComicViewerCoreWithSuspense: React.FC<Props> = ({ episodeId }) => {
const ComicViewerCoreWithSuspense: React.FC<Props> = ({ episode }) => {
return (
<Suspense fallback={null}>
<ComicViewerCore episodeId={episodeId} />
<ComicViewerCore episode={episode} />
</Suspense>
);
};
Expand Down
@@ -1,7 +1,9 @@
import { useState } from 'react';
import { useInterval, useUpdate } from 'react-use';
import { useEffect, useState } from 'react';
import { useUpdate } from 'react-use';
import styled from 'styled-components';

import type { GetEpisodeResponse } from '@wsh-2024/schema/src/api/episodes/GetEpisodeResponse';

import { ComicViewerCore } from '../../../features/viewer/components/ComicViewerCore';
import { addUnitIfNeeded } from '../../../lib/css/addUnitIfNeeded';

Expand Down Expand Up @@ -30,13 +32,12 @@ const _Wrapper = styled.div<{
`;

type Props = {
episodeId: string;
episode: GetEpisodeResponse;
};

export const ComicViewer: React.FC<Props> = ({ episodeId }) => {
export const ComicViewer: React.FC<Props> = ({ episode }) => {
// 画面のリサイズに合わせて再描画する
const rerender = useUpdate();
useInterval(rerender, 0);

const [el, ref] = useState<HTMLDivElement | null>(null);

Expand All @@ -52,10 +53,15 @@ export const ComicViewer: React.FC<Props> = ({ episodeId }) => {
// ビュアーの高さ
const viewerHeight = clamp(candidatePageHeight, MIN_VIEWER_HEIGHT, MAX_VIEWER_HEIGHT);

useEffect(() => {
window.addEventListener('resize', rerender);
return () => window.removeEventListener('resize', rerender);
}, [rerender]);

return (
<_Container ref={ref}>
<_Wrapper $maxHeight={viewerHeight}>
<ComicViewerCore episodeId={episodeId} />
<ComicViewerCore episode={episode} />
</_Wrapper>
</_Container>
);
Expand Down

0 comments on commit 2178989

Please sign in to comment.