feat: add responsive case study sharing
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback, useEffect, useRef, useState, type PointerEvent, type ReactNode } from 'react';
|
||||
import { Check, Copy, X } from 'lucide-react';
|
||||
import { useCallback, useEffect, useRef, type PointerEvent, type ReactNode } from 'react';
|
||||
import { X } from 'lucide-react';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { messagesByLocale, type Locale } from '@/i18n/content';
|
||||
import { useDismissCaseStudy } from './PortfolioRouteShell';
|
||||
import { CaseStudyShare } from './CaseStudyShare';
|
||||
import { useDrawerDrag } from './useDrawerDrag';
|
||||
import styles from './CaseStudyDrawer.module.css';
|
||||
|
||||
type CopyState = 'idle' | 'copied' | 'error';
|
||||
|
||||
export function CaseStudyDrawer({ children, locale }: { children: ReactNode; locale: Locale }) {
|
||||
const copy = messagesByLocale[locale].projects;
|
||||
const pathname = usePathname();
|
||||
@@ -21,7 +20,6 @@ export function CaseStudyDrawer({ children, locale }: { children: ReactNode; loc
|
||||
const closing = useRef(false);
|
||||
const returnFocusRef = useRef<HTMLElement | null>(null);
|
||||
const backgroundScrollY = useRef(0);
|
||||
const [copyState, setCopyState] = useState<CopyState>('idle');
|
||||
|
||||
const finishDismiss = useCallback(() => {
|
||||
const dialog = dialogRef.current;
|
||||
@@ -95,20 +93,10 @@ export function CaseStudyDrawer({ children, locale }: { children: ReactNode; loc
|
||||
useEffect(() => {
|
||||
scrollRef.current?.scrollTo({ top: 0, behavior: 'auto' });
|
||||
requestAnimationFrame(() => {
|
||||
setCopyState('idle');
|
||||
dialogRef.current?.querySelector<HTMLElement>('[data-case-study-initial-focus]')?.focus();
|
||||
});
|
||||
}, [pathname]);
|
||||
|
||||
const copyCurrentLink = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(window.location.href);
|
||||
setCopyState('copied');
|
||||
} catch {
|
||||
setCopyState('error');
|
||||
}
|
||||
};
|
||||
|
||||
const handleBackdropDown = (event: PointerEvent<HTMLDialogElement>) => {
|
||||
backdropPressed.current = event.target === event.currentTarget;
|
||||
};
|
||||
@@ -118,8 +106,6 @@ export function CaseStudyDrawer({ children, locale }: { children: ReactNode; loc
|
||||
backdropPressed.current = false;
|
||||
};
|
||||
|
||||
const feedback = copyState === 'copied' ? copy.linkCopied : copyState === 'error' ? copy.copyFailed : '';
|
||||
|
||||
return (
|
||||
<dialog
|
||||
ref={dialogRef}
|
||||
@@ -141,10 +127,7 @@ export function CaseStudyDrawer({ children, locale }: { children: ReactNode; loc
|
||||
</div>
|
||||
<span className={styles.drawerLabel}>{copy.drawerLabel}</span>
|
||||
<div className={styles.actions}>
|
||||
<button type="button" className={styles.actionButton} onClick={copyCurrentLink} aria-label={copy.copyLink}>
|
||||
{copyState === 'copied' ? <Check size={19} aria-hidden="true" /> : <Copy size={18} aria-hidden="true" />}
|
||||
<span className={styles.actionText}>{copyState === 'copied' ? copy.linkCopied : copy.copyLink}</span>
|
||||
</button>
|
||||
<CaseStudyShare locale={locale} />
|
||||
<button
|
||||
type="button"
|
||||
className={styles.iconButton}
|
||||
@@ -156,7 +139,6 @@ export function CaseStudyDrawer({ children, locale }: { children: ReactNode; loc
|
||||
<X size={21} aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
<span className={styles.liveRegion} aria-live="polite">{feedback}</span>
|
||||
</div>
|
||||
<div ref={scrollRef} className={styles.scrollArea}>{children}</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user