diff --git a/frontend/src/skeuomorphic_ws.css b/frontend/src/DesktopWorkspace.css
similarity index 88%
rename from frontend/src/skeuomorphic_ws.css
rename to frontend/src/DesktopWorkspace.css
index f2cab9f..efb4955 100644
--- a/frontend/src/skeuomorphic_ws.css
+++ b/frontend/src/DesktopWorkspace.css
@@ -6,6 +6,20 @@
min-height: 0;
}
+.skeuo-item {
+ position: absolute;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: auto;
+ cursor: grab;
+ touch-action: none;
+ transform-origin: center center;
+ transition: box-shadow 0.16s ease;
+ outline: none;
+ will-change: transform;
+}
+
.skeuo-shell {
flex: 1;
display: flex;
@@ -33,28 +47,14 @@
font-size: 0.95rem;
}
-.skeuo-item {
- position: absolute;
- display: flex;
- flex-direction: column;
- align-items: center;
- width: auto;
- cursor: grab;
- touch-action: none;
- transform-origin: center center;
- transition: transform 0.28s ease, box-shadow 0.16s ease;
- outline: none;
- will-change: transform;
-}
+
.skeuo-item__body {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
+ justify-content: center;
+ flex-grow: 1;
}
.skeuo-item:focus-visible {
@@ -68,8 +68,8 @@
}
.skeuo-item.is-tag-target .skeuo-item__card {
- outline: 1em dashed var(--accent);
- outline-offset: 1.41em;
+ outline: 0.35rem dashed var(--accent);
+ outline-offset: 0.35rem;
}
.skeuo-item.is-tag-pending .skeuo-item__card {
@@ -125,12 +125,12 @@
.skeuo-card__nav {
position: absolute;
- bottom: calc(3em * 0.707 * var(--nav-scale));
+ bottom: 1.8rem;
left: 50%;
- transform: translateX(-50%) scale(calc(0.707 * var(--nav-scale, 1)));
+ transform: translateX(-50%);
transform-origin: center;
display: flex;
- gap: 2rem;
+ gap: 1.5rem;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s ease;
@@ -145,10 +145,10 @@
display: inline-flex;
align-items: center;
justify-content: center;
- width: 3.3em;
- height: 3.3em;
- padding: 0.36em;
- border-radius: 3.3em;
+ width: 2.4em;
+ height: 2.4em;
+ padding: 0.25em;
+ border-radius: 50%;
border: none;
background: rgba(0, 0, 0, 0.55);
color: #fff;
@@ -194,9 +194,17 @@ body.skeuo-cursor-remove * {
display: flex;
align-items: center;
justify-content: center;
- box-shadow: 0 24px 72px rgba(0, 0, 0, 0.24);
+ width: 100%;
+ height: 100%;
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
overflow: hidden;
- --nav-scale: 1;
+}
+
+.skeuo-item__card img {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ display: block;
}
.skeuo-item__card--empty {
@@ -238,6 +246,7 @@ body.skeuo-cursor-remove * {
color: #3b3b3b;
max-width: 90%;
overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
+ overflow-wrap: anywhere;
+ word-break: break-word;
+ white-space: normal;
}
diff --git a/frontend/src/skeuomorphic_ws.jsx b/frontend/src/DesktopWorkspace.jsx
similarity index 61%
rename from frontend/src/skeuomorphic_ws.jsx
rename to frontend/src/DesktopWorkspace.jsx
index 24b3c8a..4887a39 100644
--- a/frontend/src/skeuomorphic_ws.jsx
+++ b/frontend/src/DesktopWorkspace.jsx
@@ -9,9 +9,13 @@ import React, {
import { resolveDocumentAssetUrl, createAssetView } from './asset_manager';
import { useAssetNavigator } from './hooks/useAssetNavigator';
import { ArrowLeftIcon, ArrowRightIcon, RefreshIcon } from './ui/icons';
+import { clamp, formatTransform } from './desktop/math';
+import { preventAll } from './desktop/events';
+import useDocumentDrag from './desktop/useDocumentDrag';
+import { DesktopProvider, useDesktopContext } from './desktop/context';
import PreviewZoomOverlay from './detail/PreviewZoomOverlay';
import { getTagColorStyle } from './utils/colors';
-import './skeuomorphic_ws.css';
+import './DesktopWorkspace.css';
const ITEM_WIDTH = 220;
const ITEM_HEIGHT = 260;
@@ -35,6 +39,42 @@ const DEBUG_DRAG = false;
const DEBUG_FOCUS = true;
const DEBUG_DROP = true;
+const readTransferData = (dataTransfer, mimeTypes) => {
+ if (!dataTransfer) {
+ return null;
+ }
+ for (let index = 0; index < mimeTypes.length; index += 1) {
+ const type = mimeTypes[index];
+ try {
+ const raw = dataTransfer.getData(type);
+ if (raw) {
+ return raw;
+ }
+ } catch (
+ // eslint-disable-next-line no-empty
+ error
+ ) {}
+ }
+ return null;
+};
+
+const parseTagTransferPayload = (event) => {
+ const raw = readTransferData(event?.dataTransfer, [
+ 'application/x-papercrate-tag',
+ 'text/papercrate-tag',
+ ]);
+ if (!raw) {
+ return null;
+ }
+ try {
+ return JSON.parse(raw);
+ } catch (
+ // eslint-disable-next-line no-empty
+ error
+ ) {}
+ return null;
+};
+
const resolveTagKey = (tag) => {
if (!tag) {
return null;
@@ -48,14 +88,15 @@ const SkeuoPreviewCard = ({
title,
ensureAssetUrl,
getDocumentAsset,
- navScale = 1,
prefetch = 3,
onNavigatorSnapshot,
+ shouldLoad = true,
+ imageSize = null,
}) => {
const navigator = useAssetNavigator({
document: doc,
assetType: 'preview',
- ensureAssetUrl,
+ ensureAssetUrl: shouldLoad ? ensureAssetUrl : null,
getAsset: getDocumentAsset,
prefetch,
});
@@ -100,7 +141,6 @@ const SkeuoPreviewCard = ({
const cardClasses = ['skeuo-item__card'];
if (!hasPreview) cardClasses.push('skeuo-item__card--empty');
const showNav = hasPreview && (cardinality > 1 || canGoPrev || canGoNext);
- const navStyle = useMemo(() => ({ '--nav-scale': navScale }), [navScale]);
return (
@@ -115,30 +155,25 @@ const SkeuoPreviewCard = ({
)}
{showNav ? (
-
+