Skip to content

Commit

Permalink
Grid ruler marker labels (#6664)
Browse files Browse the repository at this point in the history
**Problem:**

Ruler markers should show a label with the respective CSS value when
hovered.

**Fix:**

1. Show labels with the printed pin CSS when hovering a ruler marker.
For line names, show the line name. For named spans, show `span
the-area`.
2. Adjust the markers so they respect the verbatim CSS without special
treatment for span-end/start (which we could revisit in the future)
3. Adjust (and make more readable) the invididual marker skew values,
which need to be customized in a bunch of combinations (it's subtle, but
it's there!). I ended up using a bunch of named conditions, which after
some tinkering felt much more readable than a cluster of ifs or
switches. Better ideas are more than welcome tho! 🤗


https://github.com/user-attachments/assets/063adeb5-0b09-4a09-8603-77448bfd0cb2

| Config | Before | After |
|--------|---------|-----------|
| `gridColumn: auto`, `gridRow: auto` | <img width="1120"
alt="Screenshot 2024-11-20 at 15 30 23"
src="https://github.com/user-attachments/assets/c2d2b355-0312-46f4-a34c-f10f4619ddb8">
| <img width="1120" alt="Screenshot 2024-11-20 at 15 30 20"
src="https://github.com/user-attachments/assets/a733ca4c-1d77-4d26-925e-8ce4161a3989">
|
| `gridColumn: 3`, `gridRow: 1` | <img width="1120" alt="Screenshot
2024-11-20 at 15 30 36"
src="https://github.com/user-attachments/assets/b5365ca3-9d2b-4c26-ab32-1811bbf82cb4">
| <img width="1120" alt="Screenshot 2024-11-20 at 15 30 35"
src="https://github.com/user-attachments/assets/ae8a1a1c-67a5-466a-a46c-233f98553705">
|
| `gridColumn: span 2 / 4`, `gridRow: span 3` | <img width="1133"
alt="Screenshot 2024-11-20 at 15 35 51"
src="https://github.com/user-attachments/assets/dbb8d3e3-89ef-4262-90df-f222bb828c83">
| <img width="1133" alt="Screenshot 2024-11-20 at 15 35 50"
src="https://github.com/user-attachments/assets/018bd102-7331-4fbb-8ba6-8ab3316d4464">
|

<img width="1120" alt="Screenshot 2024-11-20 at 15 31 22"
src="https://github.com/user-attachments/assets/83057672-e2e5-4307-91ab-bd1a01e8a520">
<img width="1120" alt="Screenshot 2024-11-20 at 15 31 27"
src="https://github.com/user-attachments/assets/4bb71dab-d3d6-46e7-b6ec-6e10a726ae7e">
<img width="1133" alt="Screenshot 2024-11-20 at 15 31 35"
src="https://github.com/user-attachments/assets/453040c3-7151-4ff8-bfc8-73ed9925307b">






**Manual Tests:**
I hereby swear that:

- [x] I opened a hydrogen project and it loaded
- [x] I could navigate to various routes in Play mode

Fixes #6663
  • Loading branch information
ruggi authored and liady committed Dec 13, 2024
1 parent be5680a commit 3d9652e
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 39 deletions.
186 changes: 147 additions & 39 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 @@ -120,6 +119,7 @@ import { styleStringInArray } from '../../../utils/common-constants'
import { gridContainerIdentifier, type GridIdentifier } from '../../editor/store/editor-state'
import type { RulerMarkerType } from './grid-controls-ruler-markers'
import { rulerMarkerIcons } from './grid-controls-ruler-markers'
import { isFeatureEnabled } from '../../../utils/feature-switches'

const CELL_ANIMATION_DURATION = 0.15 // seconds

Expand Down Expand Up @@ -1213,9 +1213,12 @@ export const GridControlsComponent = ({ targets }: GridControlsProps) => {
)
})}
{/* Ruler markers */}
{selectedGridItems.map((path) => {
return <RulerMarkers key={`ruler-markers-${EP.toString(path)}`} path={path} />
})}
{when(
isFeatureEnabled('Grid Ruler Markers'),
selectedGridItems.map((path) => {
return <RulerMarkers key={`ruler-markers-${EP.toString(path)}`} path={path} />
}),
)}
<AbsoluteDistanceIndicators targetRootCell={targetRootCell} />
</CanvasOffsetWrapper>
</div>
Expand Down Expand Up @@ -2186,6 +2189,7 @@ function useSelectedGridItems(): ElementPath[] {
const rulerMarkerIconSize = 12 // px

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

Expand All @@ -2217,6 +2220,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 +2274,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 +2310,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 +2351,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 +2377,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 +2424,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 +2499,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(
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
}
3 changes: 3 additions & 0 deletions editor/src/utils/feature-switches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type FeatureName =
| 'Tailwind'
| 'Import Wizard'
| 'Show Debug Features'
| 'Grid Ruler Markers'

export const AllFeatureNames: FeatureName[] = [
// 'Dragging Reparents By Default', // Removing this option so that we can experiment on this later
Expand All @@ -48,6 +49,7 @@ export const AllFeatureNames: FeatureName[] = [
'Canvas Fast Selection Hack',
'Tailwind',
'Import Wizard',
'Grid Ruler Markers',
]

let FeatureSwitches: { [feature in FeatureName]: boolean } = {
Expand All @@ -72,6 +74,7 @@ let FeatureSwitches: { [feature in FeatureName]: boolean } = {
'Canvas Fast Selection Hack': true,
'Import Wizard': !IS_TEST_ENVIRONMENT,
'Show Debug Features': false,
'Grid Ruler Markers': false,
}

export const STEGANOGRAPHY_ENABLED = false
Expand Down

0 comments on commit 3d9652e

Please sign in to comment.