From e150b81190012aa5b9896839c918efab5b680766 Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Tue, 28 Oct 2025 10:41:56 +0100 Subject: [PATCH] rename skeuo to desktop --- ...euomorphic_ws.css => DesktopWorkspace.css} | 69 +- ...euomorphic_ws.jsx => DesktopWorkspace.jsx} | 1384 +++++++++-------- frontend/src/desktop/context.js | 17 + frontend/src/desktop/events.js | 17 + frontend/src/desktop/math.js | 8 + frontend/src/desktop/useDocumentDrag.js | 248 +++ frontend/src/index.jsx | 4 +- frontend/src/styles.css | 32 +- 8 files changed, 1093 insertions(+), 686 deletions(-) rename frontend/src/{skeuomorphic_ws.css => DesktopWorkspace.css} (88%) rename frontend/src/{skeuomorphic_ws.jsx => DesktopWorkspace.jsx} (61%) create mode 100644 frontend/src/desktop/context.js create mode 100644 frontend/src/desktop/events.js create mode 100644 frontend/src/desktop/math.js create mode 100644 frontend/src/desktop/useDocumentDrag.js 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 ? ( -
+