deskview
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
/* Desktop workspace styles */
|
/* Desktop workspace styles */
|
||||||
.skeuo-main {
|
.desk-main {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item {
|
.desk-item {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: block;
|
display: block;
|
||||||
width: auto;
|
width: auto;
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
will-change: transform;
|
will-change: transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-shell {
|
.desk-shell {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -27,14 +27,14 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-canvas {
|
.desk-canvas {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-empty {
|
.desk-empty {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -47,32 +47,32 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
.skeuo-item__body {
|
.desk-item__body {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item:focus-visible {
|
.desk-item:focus-visible {
|
||||||
outline: 2px solid var(--accent);
|
outline: 2px solid var(--accent);
|
||||||
outline-offset: 4px;
|
outline-offset: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item.is-dragging {
|
.desk-item.is-dragging {
|
||||||
cursor: grabbing;
|
cursor: grabbing;
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item.is-tag-target .skeuo-item__card {
|
.desk-item.is-tag-target .desk-item__card {
|
||||||
outline: 0.35rem dashed var(--accent);
|
outline: 0.35rem dashed var(--accent);
|
||||||
outline-offset: 0.35rem;
|
outline-offset: 0.35rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item.is-tag-pending .skeuo-item__card {
|
.desk-item.is-tag-pending .desk-item__card {
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item.is-filtered-out {
|
.desk-item.is-filtered-out {
|
||||||
opacity: 0.12;
|
opacity: 0.12;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
filter: blur(15px) grayscale(100%);
|
filter: blur(15px) grayscale(100%);
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
z-index: 0 !important;
|
z-index: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item__tags {
|
.desk-item__tags {
|
||||||
--tag-scale: 1;
|
--tag-scale: 1;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -112,14 +112,14 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item__tags .tag-chip {
|
.desk-item__tags .tag-chip {
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
padding: 0.18rem 0.55rem;
|
padding: 0.18rem 0.55rem;
|
||||||
gap: 0.3rem;
|
gap: 0.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.skeuo-card__nav {
|
.desk-card__nav {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 1.8rem;
|
bottom: 1.8rem;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
@@ -132,12 +132,12 @@
|
|||||||
transition: opacity 0.2s ease;
|
transition: opacity 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item__card:hover .skeuo-card__nav {
|
.desk-item__card:hover .desk-card__nav {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-card__nav-button {
|
.desk-card__nav-button {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -152,39 +152,39 @@
|
|||||||
transition: background 0.15s ease, opacity 0.15s ease;
|
transition: background 0.15s ease, opacity 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-card__nav-button:hover:not([disabled]) {
|
.desk-card__nav-button:hover:not([disabled]) {
|
||||||
background: var(--preview-nav-bg-hover);
|
background: var(--preview-nav-bg-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-card__nav-button:disabled {
|
.desk-card__nav-button:disabled {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-card__nav-button:focus-visible {
|
.desk-card__nav-button:focus-visible {
|
||||||
outline: 2px solid var(--accent);
|
outline: 2px solid var(--accent);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-card__nav-button svg {
|
.desk-card__nav-button svg {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item__tags .tag-chip--tear-pending {
|
.desk-item__tags .tag-chip--tear-pending {
|
||||||
opacity: 0.35;
|
opacity: 0.35;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.skeuo-cursor-remove,
|
body.desk-cursor-remove,
|
||||||
body.skeuo-cursor-remove * {
|
body.desk-cursor-remove * {
|
||||||
cursor: not-allowed !important;
|
cursor: not-allowed !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item__shadow {
|
.desk-item__shadow {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item__card {
|
.desk-item__card {
|
||||||
position: relative;
|
position: relative;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -196,14 +196,14 @@ body.skeuo-cursor-remove * {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item__card img {
|
.desk-item__card img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item__card--empty {
|
.desk-item__card--empty {
|
||||||
box-shadow: 0 12px 32px var(--shadow-medium);
|
box-shadow: 0 12px 32px var(--shadow-medium);
|
||||||
background:
|
background:
|
||||||
radial-gradient(circle at 42% 38%, color-mix(in oklch, var(--surface-subtle) 75%, var(--selection) 25%), color-mix(in oklch, var(--surface-subtle) 85%, var(--selection) 15%) 70%),
|
radial-gradient(circle at 42% 38%, color-mix(in oklch, var(--surface-subtle) 75%, var(--selection) 25%), color-mix(in oklch, var(--surface-subtle) 85%, var(--selection) 15%) 70%),
|
||||||
@@ -217,14 +217,14 @@ body.skeuo-cursor-remove * {
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item__placeholder {
|
.desk-item__placeholder {
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
letter-spacing: normal;
|
letter-spacing: normal;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item__empty {
|
.desk-item__empty {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -236,7 +236,7 @@ body.skeuo-cursor-remove * {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-item__title {
|
.desk-item__title {
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import React, {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import { resolveDocumentAssetUrl, createAssetView } from './asset_manager';
|
import { resolveDocumentAssetUrl, createAssetView } from './asset_manager';
|
||||||
import { useAssetNavigator } from './hooks/useAssetNavigator';
|
import { useAssetNavigator } from './hooks/useAssetNavigator';
|
||||||
import { ArrowLeftIcon, ArrowRightIcon, RefreshIcon } from './ui/icons';
|
import { ArrowLeftIcon, ArrowRightIcon } from './ui/icons';
|
||||||
|
import { createDocumentsTableHeaderActions } from './documents/DocumentsTable';
|
||||||
import { clamp, formatTransform } from './desktop/math';
|
import { clamp, formatTransform } from './desktop/math';
|
||||||
import { preventAll } from './desktop/events';
|
import { preventAll } from './desktop/events';
|
||||||
import useDocumentDrag from './desktop/useDocumentDrag';
|
import useDocumentDrag from './desktop/useDocumentDrag';
|
||||||
@@ -122,7 +123,7 @@ const readTransferData = (dataTransfer, mimeTypes) => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (DEBUG_DROP) {
|
if (DEBUG_DROP) {
|
||||||
console.warn('[skeuo] readTransferData failed for type', type, error);
|
console.warn('[desk] readTransferData failed for type', type, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,7 +141,7 @@ const parseTagTransferPayload = (event) => {
|
|||||||
try {
|
try {
|
||||||
return JSON.parse(raw);
|
return JSON.parse(raw);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('[skeuo] parseTagTransferPayload failed', error);
|
console.warn('[desk] parseTagTransferPayload failed', error);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
@@ -207,8 +208,8 @@ const DesktopPreviewCard = ({
|
|||||||
onNavigatorSnapshot,
|
onNavigatorSnapshot,
|
||||||
]);
|
]);
|
||||||
const hasPreview = Boolean(currentUrl);
|
const hasPreview = Boolean(currentUrl);
|
||||||
const cardClasses = ['skeuo-item__card'];
|
const cardClasses = ['desk-item__card'];
|
||||||
if (!hasPreview) cardClasses.push('skeuo-item__card--empty');
|
if (!hasPreview) cardClasses.push('desk-item__card--empty');
|
||||||
const showNav = hasPreview && (cardinality > 1 || canGoPrev || canGoNext);
|
const showNav = hasPreview && (cardinality > 1 || canGoPrev || canGoNext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -216,18 +217,18 @@ const DesktopPreviewCard = ({
|
|||||||
{hasPreview ? (
|
{hasPreview ? (
|
||||||
<img src={currentUrl} alt={title} />
|
<img src={currentUrl} alt={title} />
|
||||||
) : (
|
) : (
|
||||||
<div className="skeuo-item__empty">
|
<div className="desk-item__empty">
|
||||||
<div className="skeuo-item__placeholder">DOC</div>
|
<div className="desk-item__placeholder">DOC</div>
|
||||||
<div className="skeuo-item__title" title={title}>
|
<div className="desk-item__title" title={title}>
|
||||||
{title}
|
{title}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{showNav ? (
|
{showNav ? (
|
||||||
<div className="skeuo-card__nav">
|
<div className="desk-card__nav">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="skeuo-card__nav-button"
|
className="desk-card__nav-button"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
preventAll(event);
|
preventAll(event);
|
||||||
navigator.goPrev();
|
navigator.goPrev();
|
||||||
@@ -251,7 +252,7 @@ const DesktopPreviewCard = ({
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="skeuo-card__nav-button"
|
className="desk-card__nav-button"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
preventAll(event);
|
preventAll(event);
|
||||||
navigator.goNext();
|
navigator.goNext();
|
||||||
@@ -463,7 +464,7 @@ const usePreviewMetadata = (documents, getDocumentAsset, ensureAssetUrl) => {
|
|||||||
metadata = view.getPrimaryMetadata();
|
metadata = view.getPrimaryMetadata();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('[skeuo] ensureDocumentSize metadata fetch failed', error);
|
console.warn('[desk] ensureDocumentSize metadata fetch failed', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -750,15 +751,15 @@ const DesktopWorkspace = ({
|
|||||||
const focusTarget = () => {
|
const focusTarget = () => {
|
||||||
try {
|
try {
|
||||||
if (DEBUG_FOCUS) {
|
if (DEBUG_FOCUS) {
|
||||||
console.log('[skeuo] focusCanvas -> attempting focus', canvas);
|
console.log('[desk] focusCanvas -> attempting focus', canvas);
|
||||||
}
|
}
|
||||||
canvas.focus({ preventScroll: true });
|
canvas.focus({ preventScroll: true });
|
||||||
if (DEBUG_FOCUS) {
|
if (DEBUG_FOCUS) {
|
||||||
console.log('[skeuo] focusCanvas: applied focus. activeElement:', document?.activeElement);
|
console.log('[desk] focusCanvas: applied focus. activeElement:', document?.activeElement);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (DEBUG_FOCUS) {
|
if (DEBUG_FOCUS) {
|
||||||
console.warn('[skeuo] focusTarget failed to focus canvas', error);
|
console.warn('[desk] focusTarget failed to focus canvas', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -769,20 +770,20 @@ const DesktopWorkspace = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG_FOCUS) {
|
if (DEBUG_FOCUS) {
|
||||||
console.log('[skeuo] requestCanvasFocus -> scheduling deferred focus');
|
console.log('[desk] requestCanvasFocus -> scheduling deferred focus');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof window.requestAnimationFrame === 'function') {
|
if (typeof window.requestAnimationFrame === 'function') {
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
if (DEBUG_FOCUS) {
|
if (DEBUG_FOCUS) {
|
||||||
console.log('[skeuo] requestCanvasFocus -> executing deferred focus (rAF)');
|
console.log('[desk] requestCanvasFocus -> executing deferred focus (rAF)');
|
||||||
}
|
}
|
||||||
focusTarget();
|
focusTarget();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (DEBUG_FOCUS) {
|
if (DEBUG_FOCUS) {
|
||||||
console.log('[skeuo] requestCanvasFocus -> executing deferred focus (timeout)');
|
console.log('[desk] requestCanvasFocus -> executing deferred focus (timeout)');
|
||||||
}
|
}
|
||||||
focusTarget();
|
focusTarget();
|
||||||
}, 0);
|
}, 0);
|
||||||
@@ -802,9 +803,9 @@ const DesktopWorkspace = ({
|
|||||||
}
|
}
|
||||||
removalCursorActiveRef.current = active;
|
removalCursorActiveRef.current = active;
|
||||||
if (active) {
|
if (active) {
|
||||||
body.classList.add('skeuo-cursor-remove');
|
body.classList.add('desk-cursor-remove');
|
||||||
} else {
|
} else {
|
||||||
body.classList.remove('skeuo-cursor-remove');
|
body.classList.remove('desk-cursor-remove');
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -1080,7 +1081,7 @@ const syncLayoutSnapshot = useCallback(() => {
|
|||||||
|
|
||||||
const nodeEnv = typeof globalThis !== 'undefined' ? globalThis.process?.env?.NODE_ENV : undefined;
|
const nodeEnv = typeof globalThis !== 'undefined' ? globalThis.process?.env?.NODE_ENV : undefined;
|
||||||
if (nodeEnv !== 'production') {
|
if (nodeEnv !== 'production') {
|
||||||
console.log('[skeuo] canvas element', container);
|
console.log('[desk] canvas element', container);
|
||||||
}
|
}
|
||||||
|
|
||||||
const commitSize = () => {
|
const commitSize = () => {
|
||||||
@@ -1238,7 +1239,7 @@ const syncLayoutSnapshot = useCallback(() => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const container = itemRefs.current.get(docId);
|
const container = itemRefs.current.get(docId);
|
||||||
const imageNode = container?.querySelector?.('.skeuo-item__card img');
|
const imageNode = container?.querySelector?.('.desk-item__card img');
|
||||||
if (!container || !imageNode) {
|
if (!container || !imageNode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1353,24 +1354,24 @@ const syncLayoutSnapshot = useCallback(() => {
|
|||||||
async (event, doc) => {
|
async (event, doc) => {
|
||||||
if (!doc || !isTagTransfer(event) || typeof onAssignTagToDocument !== 'function') {
|
if (!doc || !isTagTransfer(event) || typeof onAssignTagToDocument !== 'function') {
|
||||||
if (DEBUG_DROP) {
|
if (DEBUG_DROP) {
|
||||||
console.log('[skeuo] handleTagDropOnDoc: drop ignored', { doc, hasTransfer: isTagTransfer(event) });
|
console.log('[desk] handleTagDropOnDoc: drop ignored', { doc, hasTransfer: isTagTransfer(event) });
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
preventAll(event);
|
preventAll(event);
|
||||||
if (DEBUG_DROP) {
|
if (DEBUG_DROP) {
|
||||||
console.log('[skeuo] handleTagDropOnDoc: drop accepted for doc', doc.id, 'event', event);
|
console.log('[desk] handleTagDropOnDoc: drop accepted for doc', doc.id, 'event', event);
|
||||||
}
|
}
|
||||||
setTagDropTargetId(null);
|
setTagDropTargetId(null);
|
||||||
|
|
||||||
const payload = parseTagTransferPayload(event);
|
const payload = parseTagTransferPayload(event);
|
||||||
if (!payload && DEBUG_DROP) {
|
if (!payload && DEBUG_DROP) {
|
||||||
console.warn('[skeuo] handleTagDropOnDoc: failed to parse payload');
|
console.warn('[desk] handleTagDropOnDoc: failed to parse payload');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!payload?.id) {
|
if (!payload?.id) {
|
||||||
if (DEBUG_DROP) {
|
if (DEBUG_DROP) {
|
||||||
console.log('[skeuo] handleTagDropOnDoc: missing tag id payload', payload);
|
console.log('[desk] handleTagDropOnDoc: missing tag id payload', payload);
|
||||||
}
|
}
|
||||||
requestCanvasFocus();
|
requestCanvasFocus();
|
||||||
return;
|
return;
|
||||||
@@ -1379,13 +1380,13 @@ const syncLayoutSnapshot = useCallback(() => {
|
|||||||
const tagId = payload.id;
|
const tagId = payload.id;
|
||||||
const sourceDocId = payload.sourceDocId || null;
|
const sourceDocId = payload.sourceDocId || null;
|
||||||
if (DEBUG_DROP) {
|
if (DEBUG_DROP) {
|
||||||
console.log('[skeuo] handleTagDropOnDoc: parsed payload', { tagId, sourceDocId });
|
console.log('[desk] handleTagDropOnDoc: parsed payload', { tagId, sourceDocId });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sourceDocId && sourceDocId === doc.id) {
|
if (sourceDocId && sourceDocId === doc.id) {
|
||||||
markActiveTagDropHandled(tagId, sourceDocId);
|
markActiveTagDropHandled(tagId, sourceDocId);
|
||||||
if (DEBUG_DROP) {
|
if (DEBUG_DROP) {
|
||||||
console.log('[skeuo] handleTagDropOnDoc: drop from same doc ignored', tagId);
|
console.log('[desk] handleTagDropOnDoc: drop from same doc ignored', tagId);
|
||||||
}
|
}
|
||||||
requestCanvasFocus();
|
requestCanvasFocus();
|
||||||
return;
|
return;
|
||||||
@@ -1397,7 +1398,7 @@ const syncLayoutSnapshot = useCallback(() => {
|
|||||||
if (alreadyAssigned) {
|
if (alreadyAssigned) {
|
||||||
markActiveTagDropHandled(tagId, sourceDocId);
|
markActiveTagDropHandled(tagId, sourceDocId);
|
||||||
if (DEBUG_DROP) {
|
if (DEBUG_DROP) {
|
||||||
console.log('[skeuo] handleTagDropOnDoc: tag already assigned', tagId);
|
console.log('[desk] handleTagDropOnDoc: tag already assigned', tagId);
|
||||||
}
|
}
|
||||||
requestCanvasFocus();
|
requestCanvasFocus();
|
||||||
return;
|
return;
|
||||||
@@ -1405,7 +1406,7 @@ const syncLayoutSnapshot = useCallback(() => {
|
|||||||
|
|
||||||
const movingBetweenDocuments = Boolean(sourceDocId && sourceDocId !== doc.id);
|
const movingBetweenDocuments = Boolean(sourceDocId && sourceDocId !== doc.id);
|
||||||
if (DEBUG_DROP) {
|
if (DEBUG_DROP) {
|
||||||
console.log('[skeuo] handleTagDropOnDoc: movingBetweenDocuments', movingBetweenDocuments);
|
console.log('[desk] handleTagDropOnDoc: movingBetweenDocuments', movingBetweenDocuments);
|
||||||
}
|
}
|
||||||
|
|
||||||
setPendingTagDocId(doc.id);
|
setPendingTagDocId(doc.id);
|
||||||
@@ -1413,14 +1414,14 @@ const syncLayoutSnapshot = useCallback(() => {
|
|||||||
await onAssignTagToDocument({ documentId: doc.id, tagId, tag: payload });
|
await onAssignTagToDocument({ documentId: doc.id, tagId, tag: payload });
|
||||||
markActiveTagDropHandled(tagId, sourceDocId);
|
markActiveTagDropHandled(tagId, sourceDocId);
|
||||||
if (DEBUG_DROP) {
|
if (DEBUG_DROP) {
|
||||||
console.log('[skeuo] handleTagDropOnDoc: assigned tag', tagId, 'to doc', doc.id);
|
console.log('[desk] handleTagDropOnDoc: assigned tag', tagId, 'to doc', doc.id);
|
||||||
}
|
}
|
||||||
if (movingBetweenDocuments && typeof onRemoveTagFromDocument === 'function') {
|
if (movingBetweenDocuments && typeof onRemoveTagFromDocument === 'function') {
|
||||||
setPendingRemovalTag({ docId: sourceDocId, tagId });
|
setPendingRemovalTag({ docId: sourceDocId, tagId });
|
||||||
try {
|
try {
|
||||||
await onRemoveTagFromDocument(sourceDocId, tagId);
|
await onRemoveTagFromDocument(sourceDocId, tagId);
|
||||||
if (DEBUG_DROP) {
|
if (DEBUG_DROP) {
|
||||||
console.log('[skeuo] handleTagDropOnDoc: removed tag from source doc', sourceDocId);
|
console.log('[desk] handleTagDropOnDoc: removed tag from source doc', sourceDocId);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setPendingRemovalTag(null);
|
setPendingRemovalTag(null);
|
||||||
@@ -1429,7 +1430,7 @@ const syncLayoutSnapshot = useCallback(() => {
|
|||||||
} finally {
|
} finally {
|
||||||
setPendingTagDocId(null);
|
setPendingTagDocId(null);
|
||||||
if (DEBUG_DROP) {
|
if (DEBUG_DROP) {
|
||||||
console.log('[skeuo] handleTagDropOnDoc: finalizing drop for tag', tagId);
|
console.log('[desk] handleTagDropOnDoc: finalizing drop for tag', tagId);
|
||||||
}
|
}
|
||||||
requestCanvasFocus();
|
requestCanvasFocus();
|
||||||
}
|
}
|
||||||
@@ -1551,7 +1552,7 @@ const syncLayoutSnapshot = useCallback(() => {
|
|||||||
event.dataTransfer.effectAllowed = 'copyMove';
|
event.dataTransfer.effectAllowed = 'copyMove';
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('[skeuo] Failed to set drag effect', error);
|
console.warn('[desk] Failed to set drag effect', error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const payload = JSON.stringify({ id: tag.id, label: tag.label, sourceDocId: doc.id });
|
const payload = JSON.stringify({ id: tag.id, label: tag.label, sourceDocId: doc.id });
|
||||||
@@ -1560,7 +1561,7 @@ const syncLayoutSnapshot = useCallback(() => {
|
|||||||
event.dataTransfer?.setData('text/papercrate-tag', payload);
|
event.dataTransfer?.setData('text/papercrate-tag', payload);
|
||||||
event.dataTransfer?.setData('text/plain', tag.label || 'Tag');
|
event.dataTransfer?.setData('text/plain', tag.label || 'Tag');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('[skeuo] Failed to populate drag data for tag', error);
|
console.warn('[desk] Failed to populate drag data for tag', error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pending = pendingDocTagDragRef.current;
|
const pending = pendingDocTagDragRef.current;
|
||||||
@@ -1591,7 +1592,7 @@ const syncLayoutSnapshot = useCallback(() => {
|
|||||||
try {
|
try {
|
||||||
event.dataTransfer.setDragImage(preview.clone, preview.offsetX, preview.offsetY);
|
event.dataTransfer.setDragImage(preview.clone, preview.offsetX, preview.offsetY);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('[skeuo] Failed to set drag image', error);
|
console.warn('[desk] Failed to set drag image', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1678,7 +1679,7 @@ const syncLayoutSnapshot = useCallback(() => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const dropEffect = event?.dataTransfer?.dropEffect || 'none';
|
const dropEffect = event?.dataTransfer?.dropEffect || 'none';
|
||||||
console.log('[skeuo] dragEnd dropEffect', dropEffect, 'dropHandled', state.dropHandled);
|
console.log('[desk] dragEnd dropEffect', dropEffect, 'dropHandled', state.dropHandled);
|
||||||
const shouldRemove =
|
const shouldRemove =
|
||||||
!state.dropHandled &&
|
!state.dropHandled &&
|
||||||
dropEffect === 'none' &&
|
dropEffect === 'none' &&
|
||||||
@@ -1687,7 +1688,7 @@ const syncLayoutSnapshot = useCallback(() => {
|
|||||||
(state.distance || 0) >= TAG_REMOVE_DISTANCE;
|
(state.distance || 0) >= TAG_REMOVE_DISTANCE;
|
||||||
|
|
||||||
if (!shouldRemove) {
|
if (!shouldRemove) {
|
||||||
console.log('[skeuo] dragEnd -> no removal. distance:', state.distance);
|
console.log('[desk] dragEnd -> no removal. distance:', state.distance);
|
||||||
scheduleShowNode();
|
scheduleShowNode();
|
||||||
requestCanvasFocus();
|
requestCanvasFocus();
|
||||||
updateRemovalCursor(false);
|
updateRemovalCursor(false);
|
||||||
@@ -1700,7 +1701,7 @@ const syncLayoutSnapshot = useCallback(() => {
|
|||||||
void (async () => {
|
void (async () => {
|
||||||
try {
|
try {
|
||||||
await onRemoveTagFromDocument(state.sourceDocId, state.tagId);
|
await onRemoveTagFromDocument(state.sourceDocId, state.tagId);
|
||||||
console.log('[skeuo] dragEnd -> removed tag due to fling');
|
console.log('[desk] dragEnd -> removed tag due to fling');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to remove tag after drag', error);
|
console.error('Failed to remove tag after drag', error);
|
||||||
scheduleShowNode();
|
scheduleShowNode();
|
||||||
@@ -1854,20 +1855,20 @@ const DesktopWorkspaceView = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="skeuo-shell">
|
<div className="desk-shell">
|
||||||
<div
|
<div
|
||||||
className="skeuo-canvas"
|
className="desk-canvas"
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
onDragOver={handleCanvasDragOver}
|
onDragOver={handleCanvasDragOver}
|
||||||
onDragLeave={handleCanvasDragLeave}
|
onDragLeave={handleCanvasDragLeave}
|
||||||
onDrop={handleCanvasDrop}
|
onDrop={handleCanvasDrop}
|
||||||
>
|
>
|
||||||
{!allSizesReady ? (
|
{!allSizesReady ? (
|
||||||
<div className="skeuo-empty">
|
<div className="desk-empty">
|
||||||
<p>Loading previews…</p>
|
<p>Loading previews…</p>
|
||||||
</div>
|
</div>
|
||||||
) : items.length === 0 ? (
|
) : items.length === 0 ? (
|
||||||
<div className="skeuo-empty">
|
<div className="desk-empty">
|
||||||
<p>No documents to show here yet. Drop files to make this space come alive.</p>
|
<p>No documents to show here yet. Drop files to make this space come alive.</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -1914,7 +1915,7 @@ const DesktopWorkspaceView = () => {
|
|||||||
activeTagSet.size === 0 || docTagKeys.some((key) => activeTagSet.has(key));
|
activeTagSet.size === 0 || docTagKeys.some((key) => activeTagSet.has(key));
|
||||||
const dropActive = tagDropTargetId === doc.id;
|
const dropActive = tagDropTargetId === doc.id;
|
||||||
const dropPending = pendingTagDocId === doc.id;
|
const dropPending = pendingTagDocId === doc.id;
|
||||||
const itemClasses = ['skeuo-item'];
|
const itemClasses = ['desk-item'];
|
||||||
if (dragging) itemClasses.push('is-dragging');
|
if (dragging) itemClasses.push('is-dragging');
|
||||||
if (dropActive) itemClasses.push('is-tag-target');
|
if (dropActive) itemClasses.push('is-tag-target');
|
||||||
if (dropPending) itemClasses.push('is-tag-pending');
|
if (dropPending) itemClasses.push('is-tag-pending');
|
||||||
@@ -1951,7 +1952,7 @@ const DesktopWorkspaceView = () => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="skeuo-item__body">
|
<div className="desk-item__body">
|
||||||
<DesktopPreviewCard
|
<DesktopPreviewCard
|
||||||
doc={doc}
|
doc={doc}
|
||||||
title={title}
|
title={title}
|
||||||
@@ -1961,7 +1962,7 @@ const DesktopWorkspaceView = () => {
|
|||||||
shouldLoad={shouldLoad}
|
shouldLoad={shouldLoad}
|
||||||
/>
|
/>
|
||||||
{tags.length > 0 && (
|
{tags.length > 0 && (
|
||||||
<div className="skeuo-item__tags" aria-hidden="true">
|
<div className="desk-item__tags" aria-hidden="true">
|
||||||
{tags.map((tag) => {
|
{tags.map((tag) => {
|
||||||
const key = tag.id || tag.label || String(tag);
|
const key = tag.id || tag.label || String(tag);
|
||||||
if (
|
if (
|
||||||
@@ -2021,7 +2022,13 @@ export const createDesktopSurface = ({ workspaceProps, renderSidebarToggle }) =>
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { currentFolderName, searchResults, onRefresh, onExit } = workspaceProps;
|
const {
|
||||||
|
currentFolderName,
|
||||||
|
searchResults,
|
||||||
|
onRefresh,
|
||||||
|
viewMode,
|
||||||
|
onViewModeChange,
|
||||||
|
} = workspaceProps;
|
||||||
const title = Array.isArray(searchResults) ? 'Search results' : currentFolderName;
|
const title = Array.isArray(searchResults) ? 'Search results' : currentFolderName;
|
||||||
const subtitle = Array.isArray(searchResults)
|
const subtitle = Array.isArray(searchResults)
|
||||||
? `${searchResults.length} matching document${searchResults.length === 1 ? '' : 's'}`
|
? `${searchResults.length} matching document${searchResults.length === 1 ? '' : 's'}`
|
||||||
@@ -2030,22 +2037,11 @@ export const createDesktopSurface = ({ workspaceProps, renderSidebarToggle }) =>
|
|||||||
const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
|
const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
|
||||||
const leading = sidebarToggle ? <>{sidebarToggle}</> : null;
|
const leading = sidebarToggle ? <>{sidebarToggle}</> : null;
|
||||||
|
|
||||||
const actions = (
|
const actions = createDocumentsTableHeaderActions({
|
||||||
<>
|
viewMode: viewMode || 'desk',
|
||||||
<button
|
onViewModeChange,
|
||||||
type="button"
|
onRefresh,
|
||||||
className="icon-button"
|
});
|
||||||
onClick={onRefresh}
|
|
||||||
aria-label="Refresh"
|
|
||||||
title="Refresh"
|
|
||||||
>
|
|
||||||
<RefreshIcon />
|
|
||||||
</button>
|
|
||||||
<button type="button" className="secondary" onClick={onExit}>
|
|
||||||
Back to List
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
key: 'workspace',
|
key: 'workspace',
|
||||||
|
|||||||
@@ -190,14 +190,14 @@ const AppLayout = () => {
|
|||||||
const [currentFolder, setCurrentFolder] = useState(null);
|
const [currentFolder, setCurrentFolder] = useState(null);
|
||||||
const [currentSubfolders, setCurrentSubfolders] = useState([]);
|
const [currentSubfolders, setCurrentSubfolders] = useState([]);
|
||||||
const [documents, setDocuments] = useState([]);
|
const [documents, setDocuments] = useState([]);
|
||||||
const [workspaceMode, setWorkspaceMode] = useState('table');
|
|
||||||
const [documentsViewMode, setDocumentsViewMode] = useState(() => {
|
const [documentsViewMode, setDocumentsViewMode] = useState(() => {
|
||||||
if (typeof window === 'undefined') {
|
if (typeof window === 'undefined') {
|
||||||
return 'list';
|
return 'list';
|
||||||
}
|
}
|
||||||
const stored = window.localStorage.getItem('papercrate_view_mode');
|
const stored = window.localStorage.getItem('papercrate_view_mode');
|
||||||
return stored === 'grid' ? 'grid' : 'list';
|
return stored === 'grid' || stored === 'desk' ? stored : 'list';
|
||||||
});
|
});
|
||||||
|
const lastNonDeskViewRef = useRef(documentsViewMode === 'desk' ? 'list' : documentsViewMode);
|
||||||
|
|
||||||
const loadThemeSettings = () => {
|
const loadThemeSettings = () => {
|
||||||
const defaults = { neutralHue: 260, mode: 'system' };
|
const defaults = { neutralHue: 260, mode: 'system' };
|
||||||
@@ -258,6 +258,12 @@ const AppLayout = () => {
|
|||||||
const initialThemeSettings = loadThemeSettings();
|
const initialThemeSettings = loadThemeSettings();
|
||||||
const [neutralHue, setNeutralHue] = useState(initialThemeSettings.neutralHue);
|
const [neutralHue, setNeutralHue] = useState(initialThemeSettings.neutralHue);
|
||||||
const [themeMode, setThemeMode] = useState(initialThemeSettings.mode);
|
const [themeMode, setThemeMode] = useState(initialThemeSettings.mode);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (documentsViewMode !== 'desk') {
|
||||||
|
lastNonDeskViewRef.current = documentsViewMode;
|
||||||
|
}
|
||||||
|
}, [documentsViewMode]);
|
||||||
const initialRowSelection = [];
|
const initialRowSelection = [];
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState(initialRowSelection);
|
const [selectedRowKeys, setSelectedRowKeys] = useState(initialRowSelection);
|
||||||
const [selectionOrder, setSelectionOrder] = useState(initialRowSelection);
|
const [selectionOrder, setSelectionOrder] = useState(initialRowSelection);
|
||||||
@@ -281,9 +287,9 @@ const AppLayout = () => {
|
|||||||
}
|
}
|
||||||
tagRemovalCursorActiveRef.current = active;
|
tagRemovalCursorActiveRef.current = active;
|
||||||
if (active) {
|
if (active) {
|
||||||
body.classList.add('skeuo-cursor-remove');
|
body.classList.add('desk-cursor-remove');
|
||||||
} else {
|
} else {
|
||||||
body.classList.remove('skeuo-cursor-remove');
|
body.classList.remove('desk-cursor-remove');
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
const refreshAccessToken = useCallback(async () => {
|
const refreshAccessToken = useCallback(async () => {
|
||||||
@@ -4641,11 +4647,9 @@ const AppLayout = () => {
|
|||||||
[ensureAssetUrl, getDocumentAsset],
|
[ensureAssetUrl, getDocumentAsset],
|
||||||
);
|
);
|
||||||
|
|
||||||
const showSkeuoWorkspace = useCallback(() => setWorkspaceMode('skeuo'), [setWorkspaceMode]);
|
|
||||||
const exitSkeuoWorkspace = useCallback(() => setWorkspaceMode('table'), [setWorkspaceMode]);
|
|
||||||
const handleDocumentsViewModeChange = useCallback((mode) => {
|
const handleDocumentsViewModeChange = useCallback((mode) => {
|
||||||
|
const next = mode === 'grid' ? 'grid' : mode === 'desk' ? 'desk' : 'list';
|
||||||
setDocumentsViewMode((previous) => {
|
setDocumentsViewMode((previous) => {
|
||||||
const next = mode === 'grid' ? 'grid' : 'list';
|
|
||||||
if (next !== previous && typeof window !== 'undefined') {
|
if (next !== previous && typeof window !== 'undefined') {
|
||||||
window.localStorage.setItem('papercrate_view_mode', next);
|
window.localStorage.setItem('papercrate_view_mode', next);
|
||||||
}
|
}
|
||||||
@@ -4653,6 +4657,13 @@ const AppLayout = () => {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleDeskExit = useCallback(() => {
|
||||||
|
const fallback = lastNonDeskViewRef.current && lastNonDeskViewRef.current !== 'desk'
|
||||||
|
? lastNonDeskViewRef.current
|
||||||
|
: 'list';
|
||||||
|
handleDocumentsViewModeChange(fallback);
|
||||||
|
}, [handleDocumentsViewModeChange]);
|
||||||
|
|
||||||
const handleTenantSelect = useCallback(
|
const handleTenantSelect = useCallback(
|
||||||
async (tenantOption, { refreshOnly = false } = {}) => {
|
async (tenantOption, { refreshOnly = false } = {}) => {
|
||||||
const requestedTenantId = tenantOption?.id ?? null;
|
const requestedTenantId = tenantOption?.id ?? null;
|
||||||
@@ -4697,7 +4708,7 @@ const AppLayout = () => {
|
|||||||
appDispatch({ type: 'SET_TENANTS', tenants: data.tenants });
|
appDispatch({ type: 'SET_TENANTS', tenants: data.tenants });
|
||||||
}
|
}
|
||||||
|
|
||||||
setWorkspaceMode('table');
|
handleDocumentsViewModeChange('list');
|
||||||
navigate('/documents', { replace: true });
|
navigate('/documents', { replace: true });
|
||||||
|
|
||||||
await Promise.all([refreshTags(), refreshCorrespondents()]);
|
await Promise.all([refreshTags(), refreshCorrespondents()]);
|
||||||
@@ -4717,7 +4728,7 @@ const AppLayout = () => {
|
|||||||
notifyApiError,
|
notifyApiError,
|
||||||
setStatusMessage,
|
setStatusMessage,
|
||||||
resetWorkspaceState,
|
resetWorkspaceState,
|
||||||
setWorkspaceMode,
|
handleDocumentsViewModeChange,
|
||||||
navigate,
|
navigate,
|
||||||
refreshTags,
|
refreshTags,
|
||||||
refreshCorrespondents,
|
refreshCorrespondents,
|
||||||
@@ -4730,7 +4741,6 @@ const AppLayout = () => {
|
|||||||
currentFolderName,
|
currentFolderName,
|
||||||
breadcrumbs,
|
breadcrumbs,
|
||||||
onRefresh: refreshCurrentFolder,
|
onRefresh: refreshCurrentFolder,
|
||||||
onShowSkeuoWorkspace: showSkeuoWorkspace,
|
|
||||||
subfolders: currentSubfolders,
|
subfolders: currentSubfolders,
|
||||||
documents,
|
documents,
|
||||||
searchResults,
|
searchResults,
|
||||||
@@ -4811,7 +4821,6 @@ const AppLayout = () => {
|
|||||||
selectedDocumentIds,
|
selectedDocumentIds,
|
||||||
selectedFolderIds,
|
selectedFolderIds,
|
||||||
setFocusedRowKey,
|
setFocusedRowKey,
|
||||||
showSkeuoWorkspace,
|
|
||||||
tagLookupById,
|
tagLookupById,
|
||||||
toggleCorrespondentFilter,
|
toggleCorrespondentFilter,
|
||||||
toggleTagFilter,
|
toggleTagFilter,
|
||||||
@@ -4970,13 +4979,15 @@ const AppLayout = () => {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const skeuoWorkspaceProps = useMemo(
|
const deskWorkspaceProps = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
documents,
|
documents,
|
||||||
searchResults,
|
searchResults,
|
||||||
breadcrumbs,
|
breadcrumbs,
|
||||||
currentFolderName,
|
currentFolderName,
|
||||||
onExit: exitSkeuoWorkspace,
|
viewMode: documentsViewMode,
|
||||||
|
onViewModeChange: handleDocumentsViewModeChange,
|
||||||
|
onExit: handleDeskExit,
|
||||||
onRefresh: refreshCurrentFolder,
|
onRefresh: refreshCurrentFolder,
|
||||||
onDocumentOpen: openDocumentPreview,
|
onDocumentOpen: openDocumentPreview,
|
||||||
resolveThumbnailUrl: resolveThumbnailUrlForDoc,
|
resolveThumbnailUrl: resolveThumbnailUrlForDoc,
|
||||||
@@ -4991,7 +5002,9 @@ const AppLayout = () => {
|
|||||||
searchResults,
|
searchResults,
|
||||||
breadcrumbs,
|
breadcrumbs,
|
||||||
currentFolderName,
|
currentFolderName,
|
||||||
exitSkeuoWorkspace,
|
documentsViewMode,
|
||||||
|
handleDocumentsViewModeChange,
|
||||||
|
handleDeskExit,
|
||||||
refreshCurrentFolder,
|
refreshCurrentFolder,
|
||||||
openDocumentPreview,
|
openDocumentPreview,
|
||||||
resolveThumbnailUrlForDoc,
|
resolveThumbnailUrlForDoc,
|
||||||
@@ -5049,10 +5062,8 @@ const AppLayout = () => {
|
|||||||
handleThumbnailRegeneration,
|
handleThumbnailRegeneration,
|
||||||
documentsTableProps,
|
documentsTableProps,
|
||||||
detailPanelProps,
|
detailPanelProps,
|
||||||
workspaceMode,
|
documentsViewMode,
|
||||||
showSkeuoWorkspace,
|
deskWorkspaceProps,
|
||||||
exitSkeuoWorkspace,
|
|
||||||
skeuoWorkspaceProps,
|
|
||||||
ensurePreviewData,
|
ensurePreviewData,
|
||||||
ensureAssetUrl,
|
ensureAssetUrl,
|
||||||
resolveApiPath,
|
resolveApiPath,
|
||||||
@@ -5109,10 +5120,8 @@ const AppLayout = () => {
|
|||||||
handleThumbnailRegeneration,
|
handleThumbnailRegeneration,
|
||||||
documentsTableProps,
|
documentsTableProps,
|
||||||
detailPanelProps,
|
detailPanelProps,
|
||||||
workspaceMode,
|
documentsViewMode,
|
||||||
showSkeuoWorkspace,
|
deskWorkspaceProps,
|
||||||
exitSkeuoWorkspace,
|
|
||||||
skeuoWorkspaceProps,
|
|
||||||
ensurePreviewData,
|
ensurePreviewData,
|
||||||
ensureAssetUrl,
|
ensureAssetUrl,
|
||||||
getDocumentAsset,
|
getDocumentAsset,
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ const DocumentsRoute = () => {
|
|||||||
documentsTableProps,
|
documentsTableProps,
|
||||||
detailPanelProps,
|
detailPanelProps,
|
||||||
detailPanelOpen,
|
detailPanelOpen,
|
||||||
workspaceMode,
|
documentsViewMode,
|
||||||
skeuoWorkspaceProps,
|
deskWorkspaceProps,
|
||||||
openTagsModal,
|
openTagsModal,
|
||||||
openCorrespondentsModal,
|
openCorrespondentsModal,
|
||||||
previewWorkspaceDocument,
|
previewWorkspaceDocument,
|
||||||
@@ -65,8 +65,8 @@ const DocumentsRoute = () => {
|
|||||||
documentsTableProps,
|
documentsTableProps,
|
||||||
detailPanelProps,
|
detailPanelProps,
|
||||||
detailPanelOpen,
|
detailPanelOpen,
|
||||||
workspaceMode,
|
viewMode: documentsViewMode,
|
||||||
skeuoWorkspaceProps,
|
deskWorkspaceProps,
|
||||||
previewWorkspaceDocument,
|
previewWorkspaceDocument,
|
||||||
previewWorkspaceEntry,
|
previewWorkspaceEntry,
|
||||||
ensureAssetUrl,
|
ensureAssetUrl,
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ export const useWorkspaceSurface = ({
|
|||||||
documentsTableProps,
|
documentsTableProps,
|
||||||
detailPanelProps,
|
detailPanelProps,
|
||||||
detailPanelOpen,
|
detailPanelOpen,
|
||||||
workspaceMode,
|
viewMode,
|
||||||
skeuoWorkspaceProps,
|
deskWorkspaceProps,
|
||||||
previewWorkspaceDocument,
|
previewWorkspaceDocument,
|
||||||
previewWorkspaceEntry,
|
previewWorkspaceEntry,
|
||||||
ensureAssetUrl,
|
ensureAssetUrl,
|
||||||
@@ -62,7 +62,7 @@ export const useWorkspaceSurface = ({
|
|||||||
detailPanelOpen,
|
detailPanelOpen,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const showPreviewWorkspace = workspaceMode !== 'skeuo' && Boolean(previewWorkspaceDocument);
|
const showPreviewWorkspace = viewMode !== 'desk' && Boolean(previewWorkspaceDocument);
|
||||||
|
|
||||||
const previewSurface = useMemo(() => {
|
const previewSurface = useMemo(() => {
|
||||||
if (!showPreviewWorkspace || !previewWorkspaceDocument) {
|
if (!showPreviewWorkspace || !previewWorkspaceDocument) {
|
||||||
@@ -95,24 +95,24 @@ export const useWorkspaceSurface = ({
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const workspaceSurface = useMemo(() => {
|
const workspaceSurface = useMemo(() => {
|
||||||
if (workspaceMode !== 'skeuo') {
|
if (viewMode !== 'desk') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return createDesktopSurface({
|
return createDesktopSurface({
|
||||||
workspaceProps: skeuoWorkspaceProps,
|
workspaceProps: deskWorkspaceProps,
|
||||||
renderSidebarToggle,
|
renderSidebarToggle,
|
||||||
});
|
});
|
||||||
}, [workspaceMode, skeuoWorkspaceProps, renderSidebarToggle]);
|
}, [viewMode, deskWorkspaceProps, renderSidebarToggle]);
|
||||||
|
|
||||||
const surface = useMemo(() => {
|
const surface = useMemo(() => {
|
||||||
if (showPreviewWorkspace) {
|
if (showPreviewWorkspace) {
|
||||||
return previewSurface;
|
return previewSurface;
|
||||||
}
|
}
|
||||||
if (workspaceMode === 'skeuo') {
|
if (viewMode === 'desk') {
|
||||||
return workspaceSurface;
|
return workspaceSurface;
|
||||||
}
|
}
|
||||||
return documentsSurface;
|
return documentsSurface;
|
||||||
}, [showPreviewWorkspace, workspaceMode, previewSurface, workspaceSurface, documentsSurface]);
|
}, [showPreviewWorkspace, viewMode, previewSurface, workspaceSurface, documentsSurface]);
|
||||||
|
|
||||||
return { surface };
|
return { surface };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const useDocumentDrag = () => {
|
|||||||
capturedTarget.releasePointerCapture(pointerId);
|
capturedTarget.releasePointerCapture(pointerId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (debugDrag) {
|
if (debugDrag) {
|
||||||
console.warn('[skeuo] releasePointerCapture failed', error);
|
console.warn('[desk] releasePointerCapture failed', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ const useDocumentDrag = () => {
|
|||||||
(event, docId) => {
|
(event, docId) => {
|
||||||
if (debugDrag) {
|
if (debugDrag) {
|
||||||
console.log(
|
console.log(
|
||||||
'[skeuo] handlePointerDown fired for doc',
|
'[desk] handlePointerDown fired for doc',
|
||||||
docId,
|
docId,
|
||||||
'button',
|
'button',
|
||||||
event.button,
|
event.button,
|
||||||
@@ -86,7 +86,7 @@ const useDocumentDrag = () => {
|
|||||||
capturedTarget.setPointerCapture(event.pointerId);
|
capturedTarget.setPointerCapture(event.pointerId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (debugDrag) {
|
if (debugDrag) {
|
||||||
console.warn('[skeuo] setPointerCapture failed', error);
|
console.warn('[desk] setPointerCapture failed', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,14 +125,14 @@ const useDocumentDrag = () => {
|
|||||||
const state = dragStateRef.current;
|
const state = dragStateRef.current;
|
||||||
if (!state) {
|
if (!state) {
|
||||||
if (debugDrag) {
|
if (debugDrag) {
|
||||||
console.log('[skeuo] handlePointerMove: no drag state for pointer', event.pointerId);
|
console.log('[desk] handlePointerMove: no drag state for pointer', event.pointerId);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (state.pointerId !== event.pointerId) {
|
if (state.pointerId !== event.pointerId) {
|
||||||
if (debugDrag) {
|
if (debugDrag) {
|
||||||
console.log(
|
console.log(
|
||||||
'[skeuo] handlePointerMove: pointer mismatch expected',
|
'[desk] handlePointerMove: pointer mismatch expected',
|
||||||
state.pointerId,
|
state.pointerId,
|
||||||
'got',
|
'got',
|
||||||
event.pointerId,
|
event.pointerId,
|
||||||
@@ -143,7 +143,7 @@ const useDocumentDrag = () => {
|
|||||||
preventAll(event);
|
preventAll(event);
|
||||||
if (state.locked) {
|
if (state.locked) {
|
||||||
if (debugDrag) {
|
if (debugDrag) {
|
||||||
console.log('[skeuo] handlePointerMove: locked drag for doc', state.docId);
|
console.log('[desk] handlePointerMove: locked drag for doc', state.docId);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,7 @@ const useDocumentDrag = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (debugDrag) {
|
if (debugDrag) {
|
||||||
console.log('[skeuo] handlePointerMove: moved doc', state.docId, 'to', clampedCenterX, clampedCenterY);
|
console.log('[desk] handlePointerMove: moved doc', state.docId, 'to', clampedCenterX, clampedCenterY);
|
||||||
}
|
}
|
||||||
recalcVisibleDocIds();
|
recalcVisibleDocIds();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
EditIcon,
|
EditIcon,
|
||||||
ViewListIcon,
|
ViewListIcon,
|
||||||
ViewGridIcon,
|
ViewGridIcon,
|
||||||
|
DesktopIcon,
|
||||||
FolderIcon,
|
FolderIcon,
|
||||||
TrashIcon,
|
TrashIcon,
|
||||||
RefreshIcon,
|
RefreshIcon,
|
||||||
@@ -197,7 +198,6 @@ const DocumentThumbnailImage = ({
|
|||||||
const DocumentsTable = ({
|
const DocumentsTable = ({
|
||||||
currentFolderName,
|
currentFolderName,
|
||||||
onRefresh,
|
onRefresh,
|
||||||
onShowSkeuoWorkspace = () => {},
|
|
||||||
subfolders,
|
subfolders,
|
||||||
documents,
|
documents,
|
||||||
searchResults,
|
searchResults,
|
||||||
@@ -272,6 +272,8 @@ const DocumentsTable = ({
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
const isGridView = viewMode === 'grid';
|
const isGridView = viewMode === 'grid';
|
||||||
|
const isDeskView = viewMode === 'desk';
|
||||||
|
const isListView = viewMode === 'list';
|
||||||
const gridIconSize = DEFAULT_GRID_ICON_SIZE;
|
const gridIconSize = DEFAULT_GRID_ICON_SIZE;
|
||||||
const handleSetViewMode = useCallback(
|
const handleSetViewMode = useCallback(
|
||||||
(nextMode) => {
|
(nextMode) => {
|
||||||
@@ -492,9 +494,9 @@ const DocumentsTable = ({
|
|||||||
<div className="view-toggle" role="group" aria-label="Change view">
|
<div className="view-toggle" role="group" aria-label="Change view">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`view-toggle__button${isGridView ? '' : ' active'}`}
|
className={`view-toggle__button${isListView ? ' active' : ''}`}
|
||||||
onClick={() => handleSetViewMode('list')}
|
onClick={() => handleSetViewMode('list')}
|
||||||
aria-pressed={!isGridView}
|
aria-pressed={isListView}
|
||||||
title="List view"
|
title="List view"
|
||||||
>
|
>
|
||||||
<ViewListIcon className="view-toggle__icon" size={18} />
|
<ViewListIcon className="view-toggle__icon" size={18} />
|
||||||
@@ -508,13 +510,19 @@ const DocumentsTable = ({
|
|||||||
>
|
>
|
||||||
<ViewGridIcon className="view-toggle__icon" size={18} />
|
<ViewGridIcon className="view-toggle__icon" size={18} />
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`view-toggle__button${isDeskView ? ' active' : ''}`}
|
||||||
|
onClick={() => handleSetViewMode('desk')}
|
||||||
|
aria-pressed={isDeskView}
|
||||||
|
title="Desk view"
|
||||||
|
>
|
||||||
|
<DesktopIcon className="view-toggle__icon" size={18} />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button className="secondary" onClick={onRefresh}>
|
<button className="secondary" onClick={onRefresh}>
|
||||||
Refresh
|
Refresh
|
||||||
</button>
|
</button>
|
||||||
<button className="secondary" type="button" onClick={onShowSkeuoWorkspace}>
|
|
||||||
Desk View
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -1050,18 +1058,19 @@ export const createDocumentsTableHeaderActions = ({
|
|||||||
viewMode,
|
viewMode,
|
||||||
onViewModeChange,
|
onViewModeChange,
|
||||||
onRefresh,
|
onRefresh,
|
||||||
onShowSkeuoWorkspace,
|
|
||||||
}) => {
|
}) => {
|
||||||
|
const isListView = viewMode === 'list';
|
||||||
const isGridView = viewMode === 'grid';
|
const isGridView = viewMode === 'grid';
|
||||||
|
const isDeskView = viewMode === 'desk';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="view-toggle" role="group" aria-label="Change view">
|
<div className="view-toggle" role="group" aria-label="Change view">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`view-toggle__button${isGridView ? '' : ' active'}`}
|
className={`view-toggle__button${isListView ? ' active' : ''}`}
|
||||||
onClick={() => onViewModeChange?.('list')}
|
onClick={() => onViewModeChange?.('list')}
|
||||||
aria-pressed={!isGridView}
|
aria-pressed={isListView}
|
||||||
title="List view"
|
title="List view"
|
||||||
>
|
>
|
||||||
<ViewListIcon className="view-toggle__icon" size={18} />
|
<ViewListIcon className="view-toggle__icon" size={18} />
|
||||||
@@ -1075,6 +1084,15 @@ export const createDocumentsTableHeaderActions = ({
|
|||||||
>
|
>
|
||||||
<ViewGridIcon className="view-toggle__icon" size={18} />
|
<ViewGridIcon className="view-toggle__icon" size={18} />
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`view-toggle__button${isDeskView ? ' active' : ''}`}
|
||||||
|
onClick={() => onViewModeChange?.('desk')}
|
||||||
|
aria-pressed={isDeskView}
|
||||||
|
title="Desk view"
|
||||||
|
>
|
||||||
|
<DesktopIcon className="view-toggle__icon" size={18} />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<span className="main-content__actions-divider" aria-hidden="true">
|
<span className="main-content__actions-divider" aria-hidden="true">
|
||||||
<MinusVerticalIcon />
|
<MinusVerticalIcon />
|
||||||
@@ -1088,9 +1106,6 @@ export const createDocumentsTableHeaderActions = ({
|
|||||||
>
|
>
|
||||||
<RefreshIcon />
|
<RefreshIcon />
|
||||||
</button>
|
</button>
|
||||||
<button className="secondary" type="button" onClick={onShowSkeuoWorkspace}>
|
|
||||||
Desk View
|
|
||||||
</button>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -1109,7 +1124,6 @@ export const createDocumentsSurface = ({
|
|||||||
viewMode,
|
viewMode,
|
||||||
onViewModeChange,
|
onViewModeChange,
|
||||||
onRefresh,
|
onRefresh,
|
||||||
onShowSkeuoWorkspace,
|
|
||||||
} = tableProps;
|
} = tableProps;
|
||||||
|
|
||||||
const title = Array.isArray(searchResults) ? 'Search results' : currentFolderName;
|
const title = Array.isArray(searchResults) ? 'Search results' : currentFolderName;
|
||||||
@@ -1121,7 +1135,6 @@ export const createDocumentsSurface = ({
|
|||||||
viewMode,
|
viewMode,
|
||||||
onViewModeChange,
|
onViewModeChange,
|
||||||
onRefresh,
|
onRefresh,
|
||||||
onShowSkeuoWorkspace,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
|
const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
|
||||||
|
|||||||
@@ -2571,11 +2571,11 @@ button.danger:hover:not([disabled]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.preview-pane--stack:hover .preview-pane__nav--overlay,
|
.preview-pane--stack:hover .preview-pane__nav--overlay,
|
||||||
.skeuo-item__card:hover .preview-pane__nav--overlay {
|
.desk-item__card:hover .preview-pane__nav--overlay {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.skeuo-card__nav {
|
.desk-card__nav {
|
||||||
bottom: 0.5rem;
|
bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user