desktop selection
This commit is contained in:
@@ -81,6 +81,22 @@
|
||||
z-index: 0 !important;
|
||||
}
|
||||
|
||||
.desk-item.is-selected {
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.desk-item.is-selected .desk-item__card {
|
||||
box-shadow:
|
||||
0 0 0 0.18rem color-mix(in oklch, var(--accent) 45%, transparent),
|
||||
0 0 0.35rem 0 color-mix(in oklch, var(--accent) 28%, transparent),
|
||||
0 12px 28px -14px color-mix(in oklch, var(--accent) 20%, transparent),
|
||||
0 10px 24px var(--shadow-medium);
|
||||
}
|
||||
|
||||
.desk-item.is-selected .desk-item__title {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.desk-item__tags {
|
||||
--tag-scale: 1;
|
||||
position: absolute;
|
||||
|
||||
@@ -11,6 +11,7 @@ import { useAssetNavigator } from './hooks/useAssetNavigator';
|
||||
import { ArrowLeftIcon, ArrowRightIcon } from './ui/icons';
|
||||
import { createDocumentsTableHeaderActions } from './documents/DocumentsPanel';
|
||||
import createWorkspaceSurfaceConfig from './documents/workspaceHeader';
|
||||
import DetailPanel from './detail/DetailPanel';
|
||||
import { clamp, formatTransform } from './desktop/math';
|
||||
import { preventAll } from './desktop/events';
|
||||
import useDocumentDrag from './desktop/useDocumentDrag';
|
||||
@@ -565,11 +566,15 @@ const DesktopWorkspace = ({
|
||||
documents = [],
|
||||
searchResults = null,
|
||||
onDocumentOpen,
|
||||
onInspectDocument = null,
|
||||
onDocumentPointerSelect = null,
|
||||
onAssignTagToDocument = null,
|
||||
onRemoveTagFromDocument = null,
|
||||
ensureAssetUrl = null,
|
||||
getDocumentAsset = () => null,
|
||||
activeTagIds = [],
|
||||
selectedDocumentIds = [],
|
||||
onClearSelection = null,
|
||||
}) => {
|
||||
const items = useMemo(() => (searchResults ? searchResults : documents), [documents, searchResults]);
|
||||
|
||||
@@ -1708,6 +1713,8 @@ const syncLayoutSnapshot = useCallback(() => {
|
||||
pendingTagDocId,
|
||||
pendingRemovalTag,
|
||||
onDocumentOpen,
|
||||
onInspectDocument,
|
||||
onDocumentPointerSelect,
|
||||
ensureAssetUrl,
|
||||
getDocumentAsset,
|
||||
handleNavigatorSnapshot,
|
||||
@@ -1724,6 +1731,8 @@ const syncLayoutSnapshot = useCallback(() => {
|
||||
closeOverlay,
|
||||
overlayOriginRect,
|
||||
overlayOriginTransform,
|
||||
selectedDocumentIds,
|
||||
onClearSelection,
|
||||
}),
|
||||
[
|
||||
activeTagSet,
|
||||
@@ -1753,6 +1762,8 @@ const syncLayoutSnapshot = useCallback(() => {
|
||||
layoutSnapshot,
|
||||
docSizeVersion,
|
||||
onDocumentOpen,
|
||||
onInspectDocument,
|
||||
onDocumentPointerSelect,
|
||||
openOverlayForDoc,
|
||||
overlayDisplay,
|
||||
overlayOriginRect,
|
||||
@@ -1766,6 +1777,8 @@ const syncLayoutSnapshot = useCallback(() => {
|
||||
tagDropTargetId,
|
||||
visibleDocIds,
|
||||
documentLookup,
|
||||
selectedDocumentIds,
|
||||
onClearSelection,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -1809,6 +1822,9 @@ const DesktopWorkspaceView = () => {
|
||||
closeOverlay,
|
||||
overlayOriginRect,
|
||||
overlayOriginTransform,
|
||||
onDocumentPointerSelect,
|
||||
selectedDocumentIds,
|
||||
onClearSelection,
|
||||
} = useDesktopContext();
|
||||
|
||||
const { handlePointerDown, handlePointerMove, handlePointerUp, handlePointerCancel } =
|
||||
@@ -1818,13 +1834,25 @@ const DesktopWorkspaceView = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="desk-shell">
|
||||
<div
|
||||
className="desk-shell"
|
||||
onPointerDown={(event) => {
|
||||
if (event.target === event.currentTarget && typeof onClearSelection === 'function') {
|
||||
onClearSelection();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="desk-canvas"
|
||||
ref={containerRef}
|
||||
onDragOver={handleCanvasDragOver}
|
||||
onDragLeave={handleCanvasDragLeave}
|
||||
onDrop={handleCanvasDrop}
|
||||
onPointerDown={(event) => {
|
||||
if (event.target === event.currentTarget && typeof onClearSelection === 'function') {
|
||||
onClearSelection();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{!allSizesReady ? (
|
||||
<div className="desk-empty">
|
||||
@@ -1882,6 +1910,8 @@ const DesktopWorkspaceView = () => {
|
||||
if (dropActive) itemClasses.push('is-tag-target');
|
||||
if (dropPending) itemClasses.push('is-tag-pending');
|
||||
if (!matchesFilter) itemClasses.push('is-filtered-out');
|
||||
const isSelected = selectedDocumentIds.includes(doc.id);
|
||||
if (isSelected) itemClasses.push('is-selected');
|
||||
const docTagTokens = docTagKeys.join(' ');
|
||||
return (
|
||||
<div
|
||||
@@ -1899,7 +1929,12 @@ const DesktopWorkspaceView = () => {
|
||||
itemRefs.current.delete(doc.id);
|
||||
}
|
||||
}}
|
||||
onPointerDown={(event) => handlePointerDown(event, doc.id)}
|
||||
onPointerDown={(event) => {
|
||||
if (typeof onDocumentPointerSelect === 'function') {
|
||||
onDocumentPointerSelect(doc.id, event);
|
||||
}
|
||||
handlePointerDown(event, doc.id);
|
||||
}}
|
||||
onPointerMove={handlePointerMove}
|
||||
onPointerUp={handlePointerUp}
|
||||
onPointerCancel={handlePointerCancel}
|
||||
@@ -1983,6 +2018,8 @@ export const createDesktopSurface = ({
|
||||
renderSidebarToggle,
|
||||
parentBreadcrumb,
|
||||
onNavigateParent,
|
||||
detailProps = null,
|
||||
detailOpen = false,
|
||||
}) => {
|
||||
if (!workspaceProps) {
|
||||
return null;
|
||||
@@ -2007,6 +2044,7 @@ export const createDesktopSurface = ({
|
||||
});
|
||||
|
||||
const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
|
||||
const detail = detailOpen && detailProps ? <DetailPanel {...detailProps} /> : null;
|
||||
const surfaceConfig = createWorkspaceSurfaceConfig({
|
||||
key: 'workspace',
|
||||
variant: 'workspace',
|
||||
@@ -2018,10 +2056,11 @@ export const createDesktopSurface = ({
|
||||
actions,
|
||||
breadcrumbs: workspaceProps?.breadcrumbs || null,
|
||||
content: <DesktopWorkspace {...workspaceProps} />,
|
||||
detail,
|
||||
});
|
||||
|
||||
return {
|
||||
...surfaceConfig,
|
||||
supportsDetail: false,
|
||||
supportsDetail: Boolean(detailProps),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -4791,6 +4791,34 @@ const AppLayout = () => {
|
||||
],
|
||||
);
|
||||
|
||||
const handleDeskInspectDocument = useCallback(
|
||||
(docId) => {
|
||||
if (!docId) {
|
||||
return;
|
||||
}
|
||||
const rowKey = resolveDocumentRowKey(docId);
|
||||
if (rowKey) {
|
||||
applySelection([rowKey], { anchor: rowKey, interactedKeys: [rowKey] });
|
||||
}
|
||||
openDetailPanel({ documentIds: [docId] });
|
||||
},
|
||||
[applySelection, openDetailPanel],
|
||||
);
|
||||
|
||||
const handleDeskDocumentPointerSelect = useCallback(
|
||||
(docId, event) => {
|
||||
if (!docId) {
|
||||
return;
|
||||
}
|
||||
const rowKey = resolveDocumentRowKey(docId);
|
||||
if (!rowKey) {
|
||||
return;
|
||||
}
|
||||
handleRowSelection(rowKey, event);
|
||||
},
|
||||
[handleRowSelection],
|
||||
);
|
||||
|
||||
const deskWorkspaceProps = useMemo(
|
||||
() => ({
|
||||
documents,
|
||||
@@ -4802,6 +4830,10 @@ const AppLayout = () => {
|
||||
onExit: handleDeskExit,
|
||||
onRefresh: refreshCurrentFolder,
|
||||
onDocumentOpen: openDocumentPreview,
|
||||
onInspectDocument: handleDeskInspectDocument,
|
||||
onDocumentPointerSelect: handleDeskDocumentPointerSelect,
|
||||
selectedDocumentIds,
|
||||
onClearSelection: clearDocumentSelection,
|
||||
resolveThumbnailUrl: resolveThumbnailUrlForDoc,
|
||||
onAssignTagToDocument: handleDocumentTagAttach,
|
||||
onRemoveTagFromDocument: handleTagRemove,
|
||||
@@ -4819,6 +4851,10 @@ const AppLayout = () => {
|
||||
handleDeskExit,
|
||||
refreshCurrentFolder,
|
||||
openDocumentPreview,
|
||||
handleDeskInspectDocument,
|
||||
handleDeskDocumentPointerSelect,
|
||||
selectedDocumentIds,
|
||||
clearDocumentSelection,
|
||||
resolveThumbnailUrlForDoc,
|
||||
handleDocumentTagAttach,
|
||||
handleTagRemove,
|
||||
|
||||
@@ -132,8 +132,18 @@ export const useWorkspaceSurface = ({
|
||||
renderSidebarToggle,
|
||||
parentBreadcrumb,
|
||||
onNavigateParent: parentBreadcrumb ? onNavigateParent : null,
|
||||
detailProps: detailPanelProps,
|
||||
detailOpen: detailPanelOpen,
|
||||
});
|
||||
}, [viewMode, deskWorkspaceProps, renderSidebarToggle, parentBreadcrumb, onNavigateParent]);
|
||||
}, [
|
||||
viewMode,
|
||||
deskWorkspaceProps,
|
||||
renderSidebarToggle,
|
||||
parentBreadcrumb,
|
||||
onNavigateParent,
|
||||
detailPanelProps,
|
||||
detailPanelOpen,
|
||||
]);
|
||||
|
||||
const surface = useMemo(() => {
|
||||
if (showPreviewWorkspace) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useCallback, useRef } from 'react';
|
||||
import { useDesktopContext } from './context';
|
||||
import { preventAll } from './events';
|
||||
import { clamp, formatTransform } from './math';
|
||||
import usePointerTap from '../ui/usePointerTap';
|
||||
|
||||
const DRAG_HYSTERESIS_PX = 4;
|
||||
const DRAG_HYSTERESIS_SQUARED = DRAG_HYSTERESIS_PX * DRAG_HYSTERESIS_PX;
|
||||
@@ -36,8 +37,33 @@ const useDocumentDrag = () => {
|
||||
recalcVisibleDocIds,
|
||||
settings,
|
||||
containerRef,
|
||||
onDocumentOpen,
|
||||
onInspectDocument,
|
||||
} = useDesktopContext();
|
||||
|
||||
const tapHandler = usePointerTap({
|
||||
delay: 220,
|
||||
onSingle: ({ data, event }) => {
|
||||
if (!data || !data.docId) {
|
||||
return;
|
||||
}
|
||||
if (event && (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)) {
|
||||
return;
|
||||
}
|
||||
openOverlayForDoc(data.docId, data.originInfo);
|
||||
},
|
||||
onDouble: ({ data }) => {
|
||||
if (!data || !data.docId) {
|
||||
return;
|
||||
}
|
||||
if (typeof onInspectDocument === 'function') {
|
||||
onInspectDocument(data.docId);
|
||||
return;
|
||||
}
|
||||
onDocumentOpen?.(data.docId);
|
||||
},
|
||||
});
|
||||
|
||||
const dragStateRef = useRef(null);
|
||||
const inertiaAnimationsRef = useRef(new Map());
|
||||
const { canvasPadding, defaultCanvasWidth, defaultCanvasHeight, debugDrag } = settings;
|
||||
@@ -197,7 +223,10 @@ const useDocumentDrag = () => {
|
||||
Number.isFinite(baseScale) && baseScale > 0 ? baseScale : 1;
|
||||
const defaultCenterX = canvasPadding + docWidth / 2;
|
||||
const defaultCenterY = canvasPadding + docHeight / 2;
|
||||
bringToFront(docId);
|
||||
const metaPressed = event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
|
||||
if (!metaPressed) {
|
||||
bringToFront(docId);
|
||||
}
|
||||
const entry = layoutRef.current.get(docId) || null;
|
||||
const centerX = typeof entry?.centerX === 'number' ? entry.centerX : defaultCenterX;
|
||||
const centerY = typeof entry?.centerY === 'number' ? entry.centerY : defaultCenterY;
|
||||
@@ -338,8 +367,8 @@ const useDocumentDrag = () => {
|
||||
const rotatedOffsetY =
|
||||
state.localPointerOffsetX * sinRot + state.localPointerOffsetY * cosRot;
|
||||
|
||||
const desiredCenterX = pointerCanvasX - rotatedOffsetX;
|
||||
const desiredCenterY = pointerCanvasY - rotatedOffsetY;
|
||||
const previousCenterX = Number.isFinite(entry.centerX) ? entry.centerX : state.originCenterX;
|
||||
const previousCenterY = Number.isFinite(entry.centerY) ? entry.centerY : state.originCenterY;
|
||||
|
||||
const absCos = Math.abs(cosRot);
|
||||
const absSin = Math.abs(sinRot);
|
||||
@@ -351,6 +380,18 @@ const useDocumentDrag = () => {
|
||||
const maxCenterX = Math.max(minCenterX, canvasWidth - canvasPadding - rotatedHalfWidth);
|
||||
const minCenterY = canvasPadding + rotatedHalfHeight;
|
||||
const maxCenterY = Math.max(minCenterY, canvasHeight - canvasPadding - rotatedHalfHeight);
|
||||
|
||||
const pointerRelativePrevX = pointerCanvasX - previousCenterX;
|
||||
const pointerRelativePrevY = pointerCanvasY - previousCenterY;
|
||||
const cosInversePrev = Math.cos(-rotationRad);
|
||||
const sinInversePrev = Math.sin(-rotationRad);
|
||||
const pointerLocalPrevX = pointerRelativePrevX * cosInversePrev - pointerRelativePrevY * sinInversePrev;
|
||||
const pointerLocalPrevY = pointerRelativePrevX * sinInversePrev + pointerRelativePrevY * cosInversePrev;
|
||||
const pointerInsideRelativeToPrev =
|
||||
Math.abs(pointerLocalPrevX) <= halfWidth && Math.abs(pointerLocalPrevY) <= halfHeight;
|
||||
|
||||
const desiredCenterX = pointerCanvasX - rotatedOffsetX;
|
||||
const desiredCenterY = pointerCanvasY - rotatedOffsetY;
|
||||
const clampedCenterX = clamp(desiredCenterX, minCenterX, maxCenterX);
|
||||
const clampedCenterY = clamp(desiredCenterY, minCenterY, maxCenterY);
|
||||
|
||||
@@ -363,19 +404,30 @@ const useDocumentDrag = () => {
|
||||
state.moved = true;
|
||||
}
|
||||
|
||||
let currentCenterX = clampedCenterX;
|
||||
let currentCenterY = clampedCenterY;
|
||||
const updated = { ...entry, centerX: currentCenterX, centerY: currentCenterY };
|
||||
layoutRef.current.set(state.docId, updated);
|
||||
|
||||
const collidedWithHorizontalEdge =
|
||||
Math.abs(desiredCenterY - clampedCenterY) > EDGE_COLLISION_THRESHOLD;
|
||||
const collidedWithVerticalEdge =
|
||||
Math.abs(desiredCenterX - clampedCenterX) > EDGE_COLLISION_THRESHOLD;
|
||||
const collidedWithEdge = collidedWithHorizontalEdge || collidedWithVerticalEdge;
|
||||
|
||||
let currentCenterX = clampedCenterX;
|
||||
let currentCenterY = clampedCenterY;
|
||||
if (collidedWithEdge && !pointerInsideRelativeToPrev) {
|
||||
currentCenterX = previousCenterX;
|
||||
currentCenterY = previousCenterY;
|
||||
}
|
||||
|
||||
const updated = { ...entry, centerX: currentCenterX, centerY: currentCenterY };
|
||||
layoutRef.current.set(state.docId, updated);
|
||||
|
||||
const offsetX = pointerCanvasX - currentCenterX;
|
||||
const offsetY = pointerCanvasY - currentCenterY;
|
||||
const cosInverseCurrent = Math.cos(-rotationRad);
|
||||
const sinInverseCurrent = Math.sin(-rotationRad);
|
||||
const pointerLocalX = offsetX * cosInverseCurrent - offsetY * sinInverseCurrent;
|
||||
const pointerLocalY = offsetX * sinInverseCurrent + offsetY * cosInverseCurrent;
|
||||
const pointerInsideCard =
|
||||
Math.abs(pointerLocalX) <= halfWidth && Math.abs(pointerLocalY) <= halfHeight;
|
||||
|
||||
const currentTimestamp =
|
||||
typeof event.timeStamp === 'number' && Number.isFinite(event.timeStamp)
|
||||
@@ -415,6 +467,14 @@ const useDocumentDrag = () => {
|
||||
state.restRotation = nextRest;
|
||||
}
|
||||
dampingOverride = ANGULAR_DAMPING + EDGE_COLLISION_EXTRA_DAMPING;
|
||||
if (!pointerInsideCard) {
|
||||
torque = 0;
|
||||
currentCenterX = entry?.centerX ?? currentCenterX;
|
||||
currentCenterY = entry?.centerY ?? currentCenterY;
|
||||
if (updated.centerX !== currentCenterX || updated.centerY !== currentCenterY) {
|
||||
layoutRef.current.set(state.docId, { ...updated, centerX: currentCenterX, centerY: currentCenterY });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state.lastClientX = event.clientX;
|
||||
@@ -522,6 +582,20 @@ const useDocumentDrag = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const rotationForOffsetDeg = state.rotation || 0;
|
||||
const rotationForOffsetRad = (rotationForOffsetDeg * Math.PI) / 180;
|
||||
const cosInverse = Math.cos(-rotationForOffsetRad);
|
||||
const sinInverse = Math.sin(-rotationForOffsetRad);
|
||||
const pointerRelativeX = pointerCanvasX - currentCenterX;
|
||||
const pointerRelativeY = pointerCanvasY - currentCenterY;
|
||||
const updatedLocalOffsetX = pointerRelativeX * cosInverse - pointerRelativeY * sinInverse;
|
||||
const updatedLocalOffsetY = pointerRelativeX * sinInverse + pointerRelativeY * cosInverse;
|
||||
if (!collidedWithEdge || pointerInsideCard) {
|
||||
state.localPointerOffsetX = updatedLocalOffsetX;
|
||||
state.localPointerOffsetY = updatedLocalOffsetY;
|
||||
}
|
||||
|
||||
if (debugDrag) {
|
||||
console.log('[desk] handlePointerMove: moved doc', state.docId, 'to', currentCenterX, currentCenterY);
|
||||
}
|
||||
@@ -563,20 +637,35 @@ const useDocumentDrag = () => {
|
||||
}
|
||||
|
||||
const docId = state.docId;
|
||||
bringToFront(docId);
|
||||
const metaPressed = event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
|
||||
if (!metaPressed) {
|
||||
bringToFront(docId);
|
||||
}
|
||||
const originInfo = {
|
||||
rotation: state.rotation || 0,
|
||||
scale: state.baseScale || 1,
|
||||
width: state.width,
|
||||
height: state.height,
|
||||
};
|
||||
const docKey = docId != null ? String(docId) : null;
|
||||
const doc = docKey ? documentLookup.get(docKey) : null;
|
||||
tapHandler(event, {
|
||||
docId,
|
||||
originInfo,
|
||||
docTitle: doc?.title || 'document',
|
||||
});
|
||||
finishDrag(event.pointerId);
|
||||
openOverlayForDoc(docId, originInfo);
|
||||
return;
|
||||
}
|
||||
finishDrag(event.pointerId);
|
||||
},
|
||||
[bringToFront, finishDrag, openOverlayForDoc, startInertiaAnimation],
|
||||
[
|
||||
bringToFront,
|
||||
documentLookup,
|
||||
finishDrag,
|
||||
startInertiaAnimation,
|
||||
tapHandler,
|
||||
],
|
||||
);
|
||||
|
||||
const handlePointerCancel = useCallback(
|
||||
|
||||
@@ -879,7 +879,7 @@ const DetailPanel = ({
|
||||
title="Open preview"
|
||||
disabled={!singleHasPreview}
|
||||
>
|
||||
<WindowMaximizeIcon />
|
||||
<WindowMaximizeIcon className="icon--flip-y" />
|
||||
</button>,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import React from 'react';
|
||||
import { ArrowUpIcon } from '../ui/icons';
|
||||
|
||||
export const createWorkspaceSurfaceConfig = ({
|
||||
title,
|
||||
subtitle = null,
|
||||
sidebarToggle = null,
|
||||
parentBreadcrumb = null,
|
||||
onNavigateParent = null,
|
||||
actions = null,
|
||||
breadcrumbs = null,
|
||||
content = null,
|
||||
@@ -14,25 +11,10 @@ export const createWorkspaceSurfaceConfig = ({
|
||||
variant = 'documents',
|
||||
key = 'documents',
|
||||
}) => {
|
||||
const showParent = parentBreadcrumb && typeof onNavigateParent === 'function';
|
||||
|
||||
const parentControl = showParent ? (
|
||||
<button
|
||||
type="button"
|
||||
className="icon-button"
|
||||
onClick={onNavigateParent}
|
||||
aria-label="Go to parent folder"
|
||||
title="Go to parent folder"
|
||||
>
|
||||
<ArrowUpIcon />
|
||||
</button>
|
||||
) : null;
|
||||
|
||||
const leading = sidebarToggle || parentControl
|
||||
const leading = sidebarToggle
|
||||
? (
|
||||
<>
|
||||
{sidebarToggle}
|
||||
{parentControl}
|
||||
</>
|
||||
)
|
||||
: null;
|
||||
|
||||
@@ -65,6 +65,11 @@ const FolderNode = ({
|
||||
className={rowClasses.join(' ')}
|
||||
draggable={canDrag}
|
||||
onClick={() => onSelect(node.id)}
|
||||
onDoubleClick={() => {
|
||||
if (canToggle) {
|
||||
onToggle(node.id);
|
||||
}
|
||||
}}
|
||||
onDragOver={(event) => onDragOver(event, node.id)}
|
||||
onDragLeave={onDragLeave}
|
||||
onDrop={(event) => onDrop(event, node.id)}
|
||||
@@ -84,9 +89,11 @@ const FolderNode = ({
|
||||
>
|
||||
{icon}
|
||||
</span>
|
||||
<span className="name">
|
||||
<span className="name-wrap">
|
||||
<FolderIcon className="folder-icon-image" size={16} />
|
||||
{node.name}
|
||||
<span className="name__label" title={node.name}>
|
||||
{node.name}
|
||||
</span>
|
||||
</span>
|
||||
{node.id !== 'root' && (
|
||||
<div className="folder-row__actions">
|
||||
|
||||
+24
-3
@@ -555,6 +555,10 @@ button.danger:hover:not([disabled]) {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.icon--flip-y {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.visually-hidden {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
@@ -671,6 +675,10 @@ button.danger:hover:not([disabled]) {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.main-content__body--workspace.main-content__body--has-detail > .desk-shell {
|
||||
margin-right: calc(-1 * var(--detail-panel-width));
|
||||
}
|
||||
|
||||
.main-content--has-detail {
|
||||
padding-right: var(--detail-panel-width);
|
||||
}
|
||||
@@ -1373,16 +1381,29 @@ button.danger:hover:not([disabled]) {
|
||||
transition: background 0.12s ease, color 0.12s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.folder-row span.name {
|
||||
.folder-row .name-wrap {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.folder-row .name-wrap .name__label {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.folder-row .folder-icon-image {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.folder-row:hover {
|
||||
background: var(--sidebar-hover-bg);
|
||||
color: var(--fg);
|
||||
@@ -2479,7 +2500,7 @@ button.danger:hover:not([disabled]) {
|
||||
}
|
||||
|
||||
.panel.detail-panel {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: min(100vw, var(--detail-panel-width));
|
||||
@@ -2491,7 +2512,7 @@ button.danger:hover:not([disabled]) {
|
||||
border-left: 1px solid var(--border);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 20;
|
||||
z-index: 1020;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
|
||||
Reference in New Issue
Block a user