qmd-lab / closeread

https://closeread.dev
MIT License
128 stars 5 forks source link

Feature: Highlighting figures #142

Open andrewpbray opened 1 week ago

andrewpbray commented 1 week ago

This issue serves to discuss new functionality proposed in #128 by @zzzhehao.

I chatted with @jimjam-slam and we've got an idea. The crop effect is very nice but it can be a bit disorienting to fully lose the context of the rest of the image when focusing on a particular bit of it. As an alternative, we could add a mask over the sticky with an opacity that would be settable, then the cropping transform would be cutting a rectangle out of that mask (revealing the sticky below) instead of cutting out everything except the rectangle. That'd have the effect of dimming every part of the sticky except what you'd interest in focusing on. If you set the mask to be the same color as the background and set it to be fully opaque, the effect would be the same as what you have here.

In terms of the interface for users, here's just a first cut:

Such as the HT1... [@cr-figure]{highlight="10%, 20%, 30%, 40%" highlight-level=".3"}

In this formulation, we lump this functionality in with the way we highlight text and code but provide a new syntax for generic rectangular highlights. We could set the color of the mask to be whatever the color of the background of the .sticky-col is - that'd have the effect of making the non-highlighted part fade into the background.

What are your thoughts on this approach?

jimjam-slam commented 1 day ago

I'm having a crack at the CSS part of this! I'd initially thought to put a clip-path on an overlay element in front. However, although it's not impossible to have a cut-out shape for the clip-path (where a region inside passes through, rather than a region inside blocking), it seems like it can't currently be done with a circle.

An alternate route might be to use a mask. Here's a demo of that approach.

This approach works with any kind of overlay background colour, image or opacity, and it can be configured to make feathered overlays (more like vignette, as well as rectangular overlays.

One weakness is that you specify the mask position in terms of .sticky-col-stack, not the image. So you'd need to either:

  1. do a bit of JS math to work out where the image is positioned with respect to the stack; or
  2. add a final child each .sticky that represents the overlay. I tried to do it with an :after pseudo element, but their styles are read-only in JS, so we can't manipulate an overlay created as a pseudo element
andrewpbray commented 16 hours ago

Ooo, that mask demo looks great! I haven't had enough coffee yet this morning for an approach to 1) to present itself, but it seems doable. One thing that I'm thinking through is how triggering cr-active will interact with these masks. To think through what this would look like...


# here the mask is transparent and on top
Here is an image. @cr-myimg.     

![](myimg.png){#cr-myimg}

# here the mask is triggered to be visible and still on top
Look here at the upper right-hand corner [@cr-myimg]{highlight=""radial-gradient(closest-side, #000 98%, #00000000) 25% 75% / 120px 120px no-repeat, linear-gradient(#000000 0 0)"} 

# here the mask returns to being transparent and on top
Here's a different sticky. @cr-para

:::{#cr-para}
hello world.
:::

(unclear to me if that's the way we'd want to pass the info through focus-effects - mask="radial..." might be better - but it'll do for now!)

Would it work to...

  1. In the Lua, check to see if there are any masks on triggers, add if so, add a .sticky-overlay to the section that is transparent. In CSS set its z to always stay on top of the stack (looks like your demo already does this).
  2. When a trigger with a mask appears, use JS to apply to change the style of the mask as in your demo.

So that's to say, maybe we just use 1 mask per section and always keep it on top? Triggers without a mask (like @cr-para) could reset the style of the overlay back to transparent. Would that save us from doing the math in 1?