Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grid ruler marker labels #6664

Merged
merged 2 commits into from
Nov 21, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 140 additions & 36 deletions editor/src/components/canvas/controls/grid-controls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ import {
getGlobalFrameOfGridCellFromMetadata,
getGridRelatedIndexes,
getGridElementPinState,
gridPositionToValue,
printPin,
getGridIdentifierContainerOrComponentPath,
gridIdentifierToString,
Expand Down Expand Up @@ -2186,6 +2185,7 @@ function useSelectedGridItems(): ElementPath[] {
const rulerMarkerIconSize = 12 // px

type RulerMarkerData = {
parentGrid: GridContainerProperties
columnStart: RulerMarkerPositionData
columnEnd: RulerMarkerPositionData
rowStart: RulerMarkerPositionData
Expand All @@ -2196,7 +2196,6 @@ type RulerMarkerPositionData = {
top: number
left: number
position: GridPositionOrSpan | null
counterpart: GridPositionOrSpan | null
bound: 'start' | 'end'
}

Expand All @@ -2217,6 +2216,8 @@ const RulerMarkers = React.memo((props: { path: ElementPath }) => {
return null
}

const parentGrid = elementMetadata.specialSizeMeasurements.parentContainerGridProperties

const originalGrid = findOriginalGrid(store.editor.jsxMetadata, EP.parentPath(props.path))
if (originalGrid == null) {
return null
Expand Down Expand Up @@ -2269,32 +2270,29 @@ const RulerMarkers = React.memo((props: { path: ElementPath }) => {
)

return {
parentGrid: parentGrid,
columnStart: {
top: gridRect.y,
left: left,
position: elementGridProperties.gridColumnStart,
counterpart: elementGridProperties.gridColumnEnd,
bound: 'start',
},
columnEnd: {
top: gridRect.y,
left: left + width,
position: elementGridProperties.gridColumnEnd,
counterpart: elementGridProperties.gridColumnStart,
bound: 'end',
},
rowStart: {
top: top,
left: gridRect.x,
position: elementGridProperties.gridRowStart,
counterpart: elementGridProperties.gridRowEnd,
bound: 'start',
},
rowEnd: {
top: top + height,
left: gridRect.x,
position: elementGridProperties.gridRowEnd,
counterpart: elementGridProperties.gridRowStart,
bound: 'end',
},
}
Expand All @@ -2308,22 +2306,37 @@ const RulerMarkers = React.memo((props: { path: ElementPath }) => {

return (
<React.Fragment>
<RulerMarkerIndicator marker={markers.columnStart} axis={'column'} />
<RulerMarkerIndicator marker={markers.columnEnd} axis={'column'} />
<RulerMarkerIndicator marker={markers.rowStart} axis={'row'} />
<RulerMarkerIndicator marker={markers.rowEnd} axis={'row'} />
<RulerMarkerIndicator
parentGrid={markers.parentGrid}
marker={markers.columnStart}
axis={'column'}
/>
<RulerMarkerIndicator
parentGrid={markers.parentGrid}
marker={markers.columnEnd}
axis={'column'}
/>
<RulerMarkerIndicator
parentGrid={markers.parentGrid}
marker={markers.rowStart}
axis={'row'}
/>
<RulerMarkerIndicator parentGrid={markers.parentGrid} marker={markers.rowEnd} axis={'row'} />
</React.Fragment>
)
})
RulerMarkers.displayName = 'RulerMarkers'

const RulerMarkerIndicator = React.memo(
(props: { marker: RulerMarkerPositionData; axis: 'row' | 'column' }) => {
(props: {
parentGrid: GridContainerProperties
marker: RulerMarkerPositionData
axis: 'row' | 'column'
}) => {
const colorTheme = useColorTheme()

const markerType = getRulerMarkerType({
position: props.marker.position,
counterpart: props.marker.counterpart,
bound: props.marker.bound,
})
const markerIcon = rulerMarkerIcons[markerType][props.axis]
Expand All @@ -2334,21 +2347,24 @@ const RulerMarkerIndicator = React.memo(
'RulerMarkerIndicator canvasScale',
)

function skewMarkerPosition(axis: 'column' | 'row') {
if (props.axis === axis) {
return rulerMarkerIconSize
} else if (markerType === 'span-end') {
return rulerMarkerIconSize - 1 // adjust span end position so it just touches the grid line
} else {
return rulerMarkerIconSize / 2
}
}

const scaledTop = props.marker.top * canvasScale
const top = scaledTop - skewMarkerPosition('column')
const top =
scaledTop -
skewMarkerPosition(props.axis === 'column', props.axis, props.marker.bound, markerType)

const scaledLeft = props.marker.left * canvasScale
const left = scaledLeft - skewMarkerPosition('row')
const left =
scaledLeft -
skewMarkerPosition(props.axis === 'row', props.axis, props.marker.bound, markerType)

const labelText = React.useMemo(() => {
if (props.marker.position == null) {
return null
}
return printPin(props.parentGrid, props.marker.position, props.axis)
}, [props.marker, props.parentGrid, props.axis])

const labelClass = 'ruler-marker-label'

return (
<div
Expand All @@ -2357,15 +2373,45 @@ const RulerMarkerIndicator = React.memo(
top: top,
left: left,
color: colorTheme.primary.value,
maxHeight: rulerMarkerIconSize,
maxWidth: rulerMarkerIconSize,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: rulerMarkerIconSize,
width: rulerMarkerIconSize,
zoom: 1 / canvasScale,
}}
css={{
[`> .${labelClass}`]: {
visibility: 'hidden',
},
':hover': {
[`> .${labelClass}`]: {
visibility: 'visible',
},
},
}}
>
{markerIcon}
{when(
labelText != null,
<div
className={labelClass}
style={{
position: 'absolute',
background: colorTheme.primary.value,
borderRadius: 2,
padding: '3px 6px',
color: colorTheme.white.value,
height: 20,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
top: props.axis === 'column' ? -23 : 0,
left: props.axis === 'column' ? 0 : undefined,
right: props.axis === 'row' ? rulerMarkerIconSize + 1 : undefined,
}}
>
{labelText}
</div>,
)}
</div>
)
},
Expand All @@ -2374,16 +2420,11 @@ RulerMarkerIndicator.displayName = 'RulerMarkerIndicator'

function getRulerMarkerType(props: {
position: GridPositionOrSpan | null
counterpart: GridPositionOrSpan | null
bound: 'start' | 'end'
}): RulerMarkerType {
const isAuto =
isAutoGridPin(props.position) ||
(props.bound === 'start' && isGridSpan(props.position) && isAutoGridPin(props.counterpart))
const isSpanStart =
props.bound === 'start' && isGridSpan(props.position) && isGridSpan(props.counterpart)
const isSpanEnd =
props.bound === 'end' && (isGridSpan(props.position) || isGridSpan(props.counterpart))
const isAuto = isAutoGridPin(props.position)
const isSpanStart = props.bound === 'start' && isGridSpan(props.position)
const isSpanEnd = props.bound === 'end' && isGridSpan(props.position)

if (isSpanStart) {
return 'span-start'
Expand Down Expand Up @@ -2454,3 +2495,66 @@ function getCellCanvasHeightFromBounds(
return acc + curr.height + padding
}, currentColumn.height)
}

// This function returns the amount of pixels used to adjust the position of
// individual ruler markers, which need specific skews based on their shape.
function skewMarkerPosition(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the comments, love it.

isOnTheSameAxis: boolean,
axis: 'column' | 'row',
bound: 'start' | 'end',
markerType: RulerMarkerType,
): number {
if (isOnTheSameAxis) {
return rulerMarkerIconSize
}

// span-end triangle, on the column
const spanEndColumn = axis === 'column' && markerType === 'span-end'
if (spanEndColumn) {
return 10
}
const pinnedEndColumn = axis === 'column' && markerType === 'pinned'
if (pinnedEndColumn) {
return 5
}
// any other ending marker, on the column
const endColumn = bound === 'end' && axis === 'column'
if (endColumn) {
return 2
}

// span-end triangle, on the row
const spanEndRow = axis === 'row' && markerType === 'span-end'
if (spanEndRow) {
return 9
}
// any other ending marker, on the row
const endRow = bound === 'end' && axis === 'row'
if (endRow) {
return 6
}

// span-start triangle, on the column
const spanStartColumn = axis === 'column' && markerType === 'span-start'
if (spanStartColumn) {
return 0
}
// any starting marker, on the column
const startColumn = bound === 'start' && axis === 'column'
if (startColumn) {
return 5
}

// span-start starting triangle, on the row
const spanStartRow = axis === 'row' && markerType === 'span-start'
if (spanStartRow) {
return 0
}
// any other starting marker, on the row
const startRow = bound === 'start' && axis === 'row'
if (startRow) {
return 4
}

return 0
}
Loading