Upload folder using huggingface_hub
Browse files
client/src/components/Refinity.tsx
CHANGED
|
@@ -223,9 +223,55 @@ const Refinity: React.FC = () => {
|
|
| 223 |
if (idx >= 0) return idx;
|
| 224 |
return Math.min(Math.max(taskVersions.length - 1, 0), flowIndex);
|
| 225 |
}, [taskVersions, currentVersionId, flowIndex]);
|
|
|
|
| 226 |
|
| 227 |
// Keyboard navigation disabled per request (use arrow buttons only)
|
| 228 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 229 |
const uploadDocx = async (file: File) => {
|
| 230 |
setUploading(true);
|
| 231 |
try {
|
|
@@ -822,7 +868,27 @@ const Refinity: React.FC = () => {
|
|
| 822 |
<div className="pointer-events-none absolute text-gray-700" style={{ left: '1.5rem', bottom: '6rem', zIndex: 2000 }}>…</div>
|
| 823 |
)}
|
| 824 |
{isCenter && (
|
| 825 |
-
<div
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 826 |
{/* Invisible first child to bypass first-child quirks while matching pill styles (kept in place) */}
|
| 827 |
<button
|
| 828 |
type="button"
|
|
@@ -834,12 +900,35 @@ const Refinity: React.FC = () => {
|
|
| 834 |
<div className="flex justify-center gap-3 w-full">
|
| 835 |
<button
|
| 836 |
type="button"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 837 |
onClick={(e) => {
|
| 838 |
e.preventDefault();
|
| 839 |
e.stopPropagation();
|
| 840 |
-
console.
|
| 841 |
selectManual(v.id);
|
| 842 |
}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 843 |
className="relative overflow-hidden inline-flex items-center justify-center gap-2 px-3 py-1.5 text-sm font-medium rounded-2xl text-white ring-1 ring-inset ring-white/50 backdrop-blur-md backdrop-brightness-110 backdrop-saturate-150 bg-violet-600/70 hover:bg-violet-700 active:translate-y-0.5 transition-all duration-200"
|
| 844 |
style={{ position: 'relative', zIndex: 3100, pointerEvents: 'auto', cursor: 'pointer', touchAction: 'manipulation' }}
|
| 845 |
>
|
|
@@ -850,7 +939,8 @@ const Refinity: React.FC = () => {
|
|
| 850 |
{(String(v.revisedBy || v.originalAuthor || '').toLowerCase() === String(username).toLowerCase() || isAdmin) && (
|
| 851 |
<button
|
| 852 |
type="button"
|
| 853 |
-
|
|
|
|
| 854 |
className="relative inline-flex items-center justify-center gap-2 px-3 py-1.5 text-sm font-medium rounded-2xl text-gray-800 ring-1 ring-inset ring-gray-300 bg-white/20 backdrop-blur-md hover:bg-gray-100 active:translate-y-0.5 transition-all duration-200"
|
| 855 |
style={{ position: 'relative', zIndex: 3100, pointerEvents: 'auto', cursor: 'pointer', touchAction: 'manipulation' }}
|
| 856 |
>
|
|
@@ -859,6 +949,7 @@ const Refinity: React.FC = () => {
|
|
| 859 |
)}
|
| 860 |
<button
|
| 861 |
type="button"
|
|
|
|
| 862 |
onClick={(e)=>{
|
| 863 |
e.preventDefault(); e.stopPropagation();
|
| 864 |
// Export single version content as simple .docx (inline changes off)
|
|
@@ -883,7 +974,8 @@ const Refinity: React.FC = () => {
|
|
| 883 |
</button>
|
| 884 |
<button
|
| 885 |
type="button"
|
| 886 |
-
|
|
|
|
| 887 |
className="relative inline-flex items-center justify-center gap-2 px-3 py-1.5 text-sm font-medium rounded-2xl text-gray-800 ring-1 ring-inset ring-gray-300 bg-white/20 backdrop-blur-md hover:bg-gray-100 active:translate-y-0.5 transition-all duration-200"
|
| 888 |
style={{ position: 'relative', zIndex: 3100, pointerEvents: 'auto', cursor: 'pointer', touchAction: 'manipulation' }}
|
| 889 |
>
|
|
@@ -892,7 +984,8 @@ const Refinity: React.FC = () => {
|
|
| 892 |
{(isAdmin || String(v.revisedBy || v.originalAuthor || '').toLowerCase() === String(username).toLowerCase()) && (
|
| 893 |
<button
|
| 894 |
type="button"
|
| 895 |
-
|
|
|
|
| 896 |
className="relative inline-flex items-center justify-center gap-2 px-3 py-1.5 text-sm font-medium rounded-2xl text-red-700 ring-1 ring-inset ring-red-300 bg-white/20 backdrop-blur-md hover:bg-red-600 hover:text-white active:translate-y-0.5 transition-all duration-200"
|
| 897 |
style={{ position: 'relative', zIndex: 3100, pointerEvents: 'auto', cursor: 'pointer', touchAction: 'manipulation' }}
|
| 898 |
>
|
|
@@ -907,6 +1000,28 @@ const Refinity: React.FC = () => {
|
|
| 907 |
);
|
| 908 |
})}
|
| 909 |
</SwiperRoot>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 910 |
|
| 911 |
{/* External V2 Revise Button removed per user request */}
|
| 912 |
|
|
|
|
| 223 |
if (idx >= 0) return idx;
|
| 224 |
return Math.min(Math.max(taskVersions.length - 1, 0), flowIndex);
|
| 225 |
}, [taskVersions, currentVersionId, flowIndex]);
|
| 226 |
+
const centerVersionId = React.useMemo(() => (taskVersions[flowIndex]?.id) || '', [taskVersions, flowIndex]);
|
| 227 |
|
| 228 |
// Keyboard navigation disabled per request (use arrow buttons only)
|
| 229 |
|
| 230 |
+
// Non-visual overlay to guarantee Revise clickability on all platforms without changing layout
|
| 231 |
+
const reviseBtnRefs = React.useRef<Record<string, HTMLButtonElement | null>>({});
|
| 232 |
+
const [reviseOverlay, setReviseOverlay] = React.useState<{ left: number; top: number; width: number; height: number; vid: string } | null>(null);
|
| 233 |
+
const updateReviseOverlay = React.useCallback(() => {
|
| 234 |
+
try {
|
| 235 |
+
const v = taskVersions[flowIndex];
|
| 236 |
+
if (!v) { setReviseOverlay(null); return; }
|
| 237 |
+
const el = reviseBtnRefs.current[v.id || ''];
|
| 238 |
+
if (!el) { setReviseOverlay(null); return; }
|
| 239 |
+
const r = el.getBoundingClientRect();
|
| 240 |
+
if (r.width === 0 || r.height === 0) { setReviseOverlay(null); return; }
|
| 241 |
+
setReviseOverlay({ left: Math.max(0, r.left), top: Math.max(0, r.top), width: r.width, height: r.height, vid: v.id });
|
| 242 |
+
} catch { setReviseOverlay(null); }
|
| 243 |
+
}, [taskVersions, flowIndex]);
|
| 244 |
+
React.useLayoutEffect(() => { updateReviseOverlay(); }, [updateReviseOverlay, isFullscreen, compareUIOpen, revDownloadOpen]);
|
| 245 |
+
React.useEffect(() => {
|
| 246 |
+
// After slide changes, measure across a few frames and after a short delay
|
| 247 |
+
let raf1 = 0, raf2 = 0, raf3 = 0;
|
| 248 |
+
const tick = () => updateReviseOverlay();
|
| 249 |
+
raf1 = window.requestAnimationFrame(() => {
|
| 250 |
+
tick();
|
| 251 |
+
raf2 = window.requestAnimationFrame(() => {
|
| 252 |
+
tick();
|
| 253 |
+
raf3 = window.requestAnimationFrame(() => tick());
|
| 254 |
+
});
|
| 255 |
+
});
|
| 256 |
+
const t = window.setTimeout(tick, 260);
|
| 257 |
+
return () => {
|
| 258 |
+
window.cancelAnimationFrame(raf1);
|
| 259 |
+
window.cancelAnimationFrame(raf2);
|
| 260 |
+
window.cancelAnimationFrame(raf3);
|
| 261 |
+
window.clearTimeout(t);
|
| 262 |
+
};
|
| 263 |
+
}, [flowIndex, centerVersionId, updateReviseOverlay]);
|
| 264 |
+
React.useEffect(() => {
|
| 265 |
+
const onResize = () => updateReviseOverlay();
|
| 266 |
+
const onScroll = () => updateReviseOverlay();
|
| 267 |
+
window.addEventListener('resize', onResize, { passive: true } as any);
|
| 268 |
+
window.addEventListener('scroll', onScroll, { passive: true } as any);
|
| 269 |
+
return () => {
|
| 270 |
+
window.removeEventListener('resize', onResize as any);
|
| 271 |
+
window.removeEventListener('scroll', onScroll as any);
|
| 272 |
+
};
|
| 273 |
+
}, [updateReviseOverlay]);
|
| 274 |
+
|
| 275 |
const uploadDocx = async (file: File) => {
|
| 276 |
setUploading(true);
|
| 277 |
try {
|
|
|
|
| 868 |
<div className="pointer-events-none absolute text-gray-700" style={{ left: '1.5rem', bottom: '6rem', zIndex: 2000 }}>…</div>
|
| 869 |
)}
|
| 870 |
{isCenter && (
|
| 871 |
+
<div
|
| 872 |
+
className="action-row absolute left-6 right-6 bottom-6 swiper-no-swiping"
|
| 873 |
+
data-version-number={v.versionNumber}
|
| 874 |
+
data-version-index={idx}
|
| 875 |
+
data-version-id={v.id}
|
| 876 |
+
data-owner={String(v.revisedBy || v.originalAuthor || '').toLowerCase() === String(username).toLowerCase() || !!isAdmin}
|
| 877 |
+
onClickCapture={(e)=> {
|
| 878 |
+
// Diagnostic: capture clicks within action row to ensure they are not swallowed by slide
|
| 879 |
+
const t = e.target as HTMLElement;
|
| 880 |
+
console.debug('[VF] action-row click(capture)', {
|
| 881 |
+
idx,
|
| 882 |
+
versionId: v.id,
|
| 883 |
+
buttonData: t?.dataset || {},
|
| 884 |
+
targetTag: t?.tagName,
|
| 885 |
+
targetClasses: t?.className
|
| 886 |
+
});
|
| 887 |
+
}}
|
| 888 |
+
onMouseEnter={()=>{ updateReviseOverlay(); }}
|
| 889 |
+
onMouseMove={()=>{ updateReviseOverlay(); }}
|
| 890 |
+
style={{ pointerEvents: 'auto', transform: 'translateZ(0)', zIndex: 3000 }}
|
| 891 |
+
>
|
| 892 |
{/* Invisible first child to bypass first-child quirks while matching pill styles (kept in place) */}
|
| 893 |
<button
|
| 894 |
type="button"
|
|
|
|
| 900 |
<div className="flex justify-center gap-3 w-full">
|
| 901 |
<button
|
| 902 |
type="button"
|
| 903 |
+
data-btn="revise"
|
| 904 |
+
ref={(el)=>{ reviseBtnRefs.current[v.id] = el; }}
|
| 905 |
+
onClickCapture={(e)=>{ e.stopPropagation(); }}
|
| 906 |
+
onPointerDown={(e)=>{ e.stopPropagation(); }}
|
| 907 |
+
onPointerUp={(e)=>{ e.stopPropagation(); }}
|
| 908 |
onClick={(e) => {
|
| 909 |
e.preventDefault();
|
| 910 |
e.stopPropagation();
|
| 911 |
+
console.debug('[VF] Revise click', { idx, versionId: v.id, versionNumber: v.versionNumber });
|
| 912 |
selectManual(v.id);
|
| 913 |
}}
|
| 914 |
+
onMouseEnter={(e) => {
|
| 915 |
+
// Diagnostic: inspect computed styles which could affect clickability
|
| 916 |
+
try {
|
| 917 |
+
const el = e.currentTarget as HTMLElement;
|
| 918 |
+
const elCS = window.getComputedStyle(el);
|
| 919 |
+
const parent = el.parentElement;
|
| 920 |
+
const parentCS = parent ? window.getComputedStyle(parent) : null;
|
| 921 |
+
const row = el.closest('.action-row') as HTMLElement | null;
|
| 922 |
+
const rowCS = row ? window.getComputedStyle(row) : null;
|
| 923 |
+
console.debug('[VF] Revise hover styles', {
|
| 924 |
+
idx,
|
| 925 |
+
versionId: v.id,
|
| 926 |
+
el: { zIndex: elCS.zIndex, pointerEvents: elCS.pointerEvents, position: elCS.position },
|
| 927 |
+
parent: parentCS ? { zIndex: parentCS.zIndex, pointerEvents: parentCS.pointerEvents, position: parentCS.position } : null,
|
| 928 |
+
row: rowCS ? { zIndex: rowCS.zIndex, pointerEvents: rowCS.pointerEvents, position: rowCS.position } : null
|
| 929 |
+
});
|
| 930 |
+
} catch {}
|
| 931 |
+
}}
|
| 932 |
className="relative overflow-hidden inline-flex items-center justify-center gap-2 px-3 py-1.5 text-sm font-medium rounded-2xl text-white ring-1 ring-inset ring-white/50 backdrop-blur-md backdrop-brightness-110 backdrop-saturate-150 bg-violet-600/70 hover:bg-violet-700 active:translate-y-0.5 transition-all duration-200"
|
| 933 |
style={{ position: 'relative', zIndex: 3100, pointerEvents: 'auto', cursor: 'pointer', touchAction: 'manipulation' }}
|
| 934 |
>
|
|
|
|
| 939 |
{(String(v.revisedBy || v.originalAuthor || '').toLowerCase() === String(username).toLowerCase() || isAdmin) && (
|
| 940 |
<button
|
| 941 |
type="button"
|
| 942 |
+
data-btn="edit"
|
| 943 |
+
onClick={(e)=>{ e.preventDefault(); e.stopPropagation(); console.debug('[VF] Edit click', { idx, versionId: v.id }); setCurrentVersionId(v.id); setEditingVersionId(v.id); setStage('editor'); }}
|
| 944 |
className="relative inline-flex items-center justify-center gap-2 px-3 py-1.5 text-sm font-medium rounded-2xl text-gray-800 ring-1 ring-inset ring-gray-300 bg-white/20 backdrop-blur-md hover:bg-gray-100 active:translate-y-0.5 transition-all duration-200"
|
| 945 |
style={{ position: 'relative', zIndex: 3100, pointerEvents: 'auto', cursor: 'pointer', touchAction: 'manipulation' }}
|
| 946 |
>
|
|
|
|
| 949 |
)}
|
| 950 |
<button
|
| 951 |
type="button"
|
| 952 |
+
data-btn="download"
|
| 953 |
onClick={(e)=>{
|
| 954 |
e.preventDefault(); e.stopPropagation();
|
| 955 |
// Export single version content as simple .docx (inline changes off)
|
|
|
|
| 974 |
</button>
|
| 975 |
<button
|
| 976 |
type="button"
|
| 977 |
+
data-btn="compare"
|
| 978 |
+
onClick={(e) => { e.preventDefault(); e.stopPropagation(); console.debug('[VF] Compare click', { idx, versionId: v.id }); setCompareUIOpen(true); if (!compareA) setCompareA(v.id); }}
|
| 979 |
className="relative inline-flex items-center justify-center gap-2 px-3 py-1.5 text-sm font-medium rounded-2xl text-gray-800 ring-1 ring-inset ring-gray-300 bg-white/20 backdrop-blur-md hover:bg-gray-100 active:translate-y-0.5 transition-all duration-200"
|
| 980 |
style={{ position: 'relative', zIndex: 3100, pointerEvents: 'auto', cursor: 'pointer', touchAction: 'manipulation' }}
|
| 981 |
>
|
|
|
|
| 984 |
{(isAdmin || String(v.revisedBy || v.originalAuthor || '').toLowerCase() === String(username).toLowerCase()) && (
|
| 985 |
<button
|
| 986 |
type="button"
|
| 987 |
+
data-btn="delete"
|
| 988 |
+
onClick={(e)=>{ e.preventDefault(); e.stopPropagation(); console.debug('[VF] Delete click', { idx, versionId: v.id }); deleteVersion(v.id); }}
|
| 989 |
className="relative inline-flex items-center justify-center gap-2 px-3 py-1.5 text-sm font-medium rounded-2xl text-red-700 ring-1 ring-inset ring-red-300 bg-white/20 backdrop-blur-md hover:bg-red-600 hover:text-white active:translate-y-0.5 transition-all duration-200"
|
| 990 |
style={{ position: 'relative', zIndex: 3100, pointerEvents: 'auto', cursor: 'pointer', touchAction: 'manipulation' }}
|
| 991 |
>
|
|
|
|
| 1000 |
);
|
| 1001 |
})}
|
| 1002 |
</SwiperRoot>
|
| 1003 |
+
{reviseOverlay && createPortal(
|
| 1004 |
+
<button
|
| 1005 |
+
aria-label="Revise overlay"
|
| 1006 |
+
style={{
|
| 1007 |
+
position: 'fixed',
|
| 1008 |
+
left: `${reviseOverlay.left}px`,
|
| 1009 |
+
top: `${reviseOverlay.top}px`,
|
| 1010 |
+
width: `${reviseOverlay.width}px`,
|
| 1011 |
+
height: `${reviseOverlay.height}px`,
|
| 1012 |
+
background: 'transparent',
|
| 1013 |
+
border: 'none',
|
| 1014 |
+
padding: 0,
|
| 1015 |
+
margin: 0,
|
| 1016 |
+
cursor: 'pointer',
|
| 1017 |
+
zIndex: 2147483000
|
| 1018 |
+
}}
|
| 1019 |
+
onClick={(e)=>{ e.preventDefault(); e.stopPropagation(); selectManual(reviseOverlay.vid); }}
|
| 1020 |
+
onPointerDown={(e)=>{ e.stopPropagation(); }}
|
| 1021 |
+
onPointerUp={(e)=>{ e.stopPropagation(); }}
|
| 1022 |
+
/>,
|
| 1023 |
+
document.body
|
| 1024 |
+
)}
|
| 1025 |
|
| 1026 |
{/* External V2 Revise Button removed per user request */}
|
| 1027 |
|