Merge branch 'feature/site-features-and-mockup'

This commit is contained in:
Mina Choi 2026-09-21 13:57:43 +09:00
commit 8d6e6d7cd0
5 changed files with 52 additions and 56 deletions

View File

@ -1,6 +1,7 @@
import {useEffect, useRef} from 'react';
import type {ReactNode} from 'react';
import {X} from 'lucide-react';
import {useScrollLock} from './use-scroll-lock';
/**
* () · () .
@ -29,30 +30,15 @@ export function Modal({
const onCloseRef = useRef(onClose);
onCloseRef.current = onClose;
useScrollLock(open);
useEffect(() => {
if (!open) return;
const onKey = (event: KeyboardEvent) => {
if (event.key === 'Escape') onCloseRef.current();
};
const scrollY = window.scrollY;
const body = document.body;
const prevPosition = body.style.position;
const prevTop = body.style.top;
const prevWidth = body.style.width;
const prevOverflow = body.style.overflow;
body.style.position = 'fixed';
body.style.top = `-${scrollY}px`;
body.style.width = '100%';
body.style.overflow = 'hidden';
window.addEventListener('keydown', onKey);
return () => {
body.style.position = prevPosition;
body.style.top = prevTop;
body.style.width = prevWidth;
body.style.overflow = prevOverflow;
window.scrollTo(0, scrollY);
window.removeEventListener('keydown', onKey);
};
return () => window.removeEventListener('keydown', onKey);
}, [open]);
if (!open) return null;

View File

@ -3,3 +3,4 @@ export {Carousel, CarouselSlide} from './Carousel';
export {Card, Chip, Field, ActionLink} from './primitives';
export {ShowMore} from './ShowMore';
export {Modal} from './Modal';
export {useScrollLock} from './use-scroll-lock';

View File

@ -0,0 +1,39 @@
/**
* · ** .**
*
* (2026-09-21, : "이거 목업 하나만 해결하면 끝이야? 훅으로 만들어놓던가")
* · Modal · GallerySection · EventSection .
*
* .
* . `index.css` `html { scroll-behavior: smooth }`
* `window.scrollTo` "위로 튀었다 내려오는"
* `scroll-behavior: auto` .
*/
import {useEffect} from 'react';
export function useScrollLock(active: boolean) {
useEffect(() => {
if (!active) return;
const scrollY = window.scrollY;
const body = document.body;
const prevPosition = body.style.position;
const prevTop = body.style.top;
const prevWidth = body.style.width;
const prevOverflow = body.style.overflow;
body.style.position = 'fixed';
body.style.top = `-${scrollY}px`;
body.style.width = '100%';
body.style.overflow = 'hidden';
return () => {
body.style.position = prevPosition;
body.style.top = prevTop;
body.style.width = prevWidth;
body.style.overflow = prevOverflow;
const root = document.documentElement;
const prevScrollBehavior = root.style.scrollBehavior;
root.style.scrollBehavior = 'auto';
window.scrollTo(0, scrollY);
root.style.scrollBehavior = prevScrollBehavior;
};
}, [active]);
}

View File

@ -2,7 +2,7 @@ import {useCallback, useEffect, useState} from 'react';
import {ChevronLeft, ChevronRight, X} from 'lucide-react';
import {useSite} from '@site/lib/site-context';
import {galleryImages} from '@site/lib/derive';
import {Carousel, CarouselSlide, Section} from '@site/lib/ui';
import {Carousel, CarouselSlide, Section, useScrollLock} from '@site/lib/ui';
/**
* .
@ -29,6 +29,8 @@ export function GallerySection() {
// 크게 보기 중에는 Esc 로 닫고 좌우 키로 넘긴다. 뒤 배경은 스크롤을 잠근다 —
// 잠그지 않으면 모달 위에서 휠을 굴렸을 때 뒤 페이지가 밀린다.
useScrollLock(openIndex !== null);
useEffect(() => {
if (openIndex === null) return;
const onKey = (event: KeyboardEvent) => {
@ -36,25 +38,8 @@ export function GallerySection() {
if (event.key === 'ArrowLeft') step(-1);
if (event.key === 'ArrowRight') step(1);
};
const scrollY = window.scrollY;
const body = document.body;
const prevPosition = body.style.position;
const prevTop = body.style.top;
const prevWidth = body.style.width;
const prevOverflow = body.style.overflow;
body.style.position = 'fixed';
body.style.top = `-${scrollY}px`;
body.style.width = '100%';
body.style.overflow = 'hidden';
window.addEventListener('keydown', onKey);
return () => {
body.style.position = prevPosition;
body.style.top = prevTop;
body.style.width = prevWidth;
body.style.overflow = prevOverflow;
window.scrollTo(0, scrollY);
window.removeEventListener('keydown', onKey);
};
return () => window.removeEventListener('keydown', onKey);
}, [openIndex, close, step]);
if (images.length === 0) return null;

View File

@ -18,7 +18,7 @@
* .
*/
import {useCallback, useEffect, useState} from 'react';
import {ShowMore} from '@site/lib/ui';
import {ShowMore, useScrollLock} from '@site/lib/ui';
import {X} from 'lucide-react';
import type {EventItem} from '@o2o/shared';
import {useSite} from '@site/lib/site-context';
@ -90,30 +90,15 @@ export function EventSection() {
const close = useCallback(() => setOpen(null), []);
// 창이 열려 있는 동안 Esc 로 닫고 뒤 배경 스크롤을 잠근다 — 안 잠그면 창 위에서 뒤가 밀린다.
useScrollLock(open !== null);
useEffect(() => {
if (open === null) return;
const onKey = (event: KeyboardEvent) => {
if (event.key === 'Escape') close();
};
const scrollY = window.scrollY;
const body = document.body;
const prevPosition = body.style.position;
const prevTop = body.style.top;
const prevWidth = body.style.width;
const prevOverflow = body.style.overflow;
body.style.position = 'fixed';
body.style.top = `-${scrollY}px`;
body.style.width = '100%';
body.style.overflow = 'hidden';
window.addEventListener('keydown', onKey);
return () => {
body.style.position = prevPosition;
body.style.top = prevTop;
body.style.width = prevWidth;
body.style.overflow = prevOverflow;
window.scrollTo(0, scrollY);
window.removeEventListener('keydown', onKey);
};
return () => window.removeEventListener('keydown', onKey);
}, [open, close]);
if (parsed.items.length === 0) return null;