-
Notifications
You must be signed in to change notification settings - Fork 0
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
feat: Tree node styling. #592
Conversation
A few notes: * Our Tailwind config inverts the blue primary and secondary colors wrt. the document. (By my recollection, I think this was intentional and had something to do with the corresponding hover colors.) * Ann's document lists "red secondary" twice, once as #cd3764 and once as #f1685e. I believe #cd3764 was added late in the process and therefore I've called it "red tertiary" in this commit. * Ditto for "grey secondary," but in this case, the hex RGB value given for the 2nd occurrence of "grey secondary" does not match the color swatch. The hex value is the same as the 1st occurrence of "grey secondary" and therefore I've used the hex RGB value I measured by sampling the swatch in the document (which is #d4d4d4). I've called this "grey quaternary" in the Tailwind config.
This will become more useful in the next couple of commits.
Deploying with Cloudflare Pages
|
I'm not going overboard here because we are likely to toss the current tree implementation, but I'd like to get closer to the design spec for our upcoming testing. |
We don't use all of these at the moment, but it's easy to forget these are necessary, so we might as well define them in advance.
("Mostly" because some of these nodes should be filled a solid color with white text.) The summary commit message describes the only behavioral change in this commit, but I've buried the lede: this commit also majorly refactors how we assign classes to nodes & edges in the tree by using Tailwind CSS classes, rather than injecting raw `style` CSS attributes. At the moment, this doesn't buy us much and instead feels a bit like a violation of DRY, but it does give us a lot more flexibility in styling, which the next few commits will take advantage of.
The following flavors aren't selectable, and therefore we don't show hover for them: * `with` in `match ... with`. * Pattern boxes. * Pattern constructors. * Pattern applications. (Notably, pattern binds are selectable because we can rename them.) This implementation deviates from the design spec by making the width of the outline 4px, rather than 2px. I think 2px is a bit too thin, at least for our current overall style.
Per the Tailwind CSS docs, this is a 6px radius, which is what the UI design spec calls for.
I had been wondering separately what was the difference between `ring` and `outline` and finally stumbled across an explanation of why `ring` was added in the first place: tailwindlabs/tailwindcss#7649 It turns out that on Safari, outlines don't follow the border of the element they're outlining: they are always squared off. Tailwind CSS addressed this by adding `ring`, so for our purposes, this is what we should be using.
There's still some work to be done here, but this is a good approximation of the design spec. Among the things that remain to be done are: * We don't draw any labels on most syntax nodes. * The size of the label and the contrast need some work. * The single-glyph labels render like relatively flat ellipses rather than nice circles like the 3-glyph labels do. We might be able to fake this by padding out the single-glyph labels to 3 (spaces on either side), or perhaps with a bit of min-width magic.
With this commit, we pretty closely match the UI design spec for tree styling, with a few exceptions: * Holes are not rendered as a circle. * We don't have an `=` node for `let`s. * Value constructor and function `apply` nodes read just `apply` rather than `apply function`. We need to think about this a bit in the context of patterns, where `apply` only ever appears with a value constructor and we don't want students to get confused. Note that there are a few node types that weren't specified in the UI design spec (e.g., type constructors). At the moment, these are rendered in black, and we'll need to choose some colors for these. Also, nodes that appear in patterns are also rendered in black. I'm guessing this is a leftover from a debate we had a few months ago about whether patterns should be treated specially other than the box drawn around them. This will be corrected in a subsequent commit. Finally, the body content I've chosen here for some syntax nodes (e.g., `function type`) should be considered just placeholders for now. We should finalize the terms we use for these at a later date. (One complication is that they should be reasonably short, so that they don't take up too much space in the tree.)
6cc5c91
to
88eef4c
Compare
This is pretty close to the final design for expression trees (ignoring the changes we've made to edges). Off the top of my head, we still need:
2 and 3 will probably require some bikeshedding and 1 will take me some time to figure out. Therefore, I think this is ready for review. (And of course, this PR doesn't do anything about rendering type trees or top-level definition names.) Note: yes, there is quite a bit of repetitive code in the Tailwind class functions. We should definitely take advantage of some |
BTW, there are a few things that I don't like about the design spec now that we've implemented most of it in a real application. For example, I don't think the green selection ring works well. I will compile a list of these when I get a chance, and we can discuss some alternatives. I encourage everyone to do the same after you've had a chance to play with the changes in this PR. |
Previously they were rendered in black.
4547784
to
986024d
Compare
In this PR, there's one notable deviation from the UI design spec. I've placed the "P" label for patterns at the midway point of the top edge, rather than in the upper right corner as the spec calls for. This PR: The spec: I did that because other "syntax" nodes like (Hmm, it now occurs to me that maybe we should treat constructors as syntax nodes?) |
@@ -146,6 +146,7 @@ function flavorLabel(flavor: NodeFlavor): string { | |||
} | |||
|
|||
const primerNodeTypeName = "primer"; | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, the lack of line breaks were intentional. This is all part of defining a "primer node", and I like to group related definitions (though maybe it's a bit odd that there is then a blank line within PrimerNode
.
Anyway, it really doesn't matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found it hard to read and follow, personally.
return "border-black-primary outline-black-primary"; | ||
return "border-black-primary outline-black-primary".concat( | ||
commonHoverClasses | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a shame we can't easily reflect that these are precisely the nodes with numeric IDs. But I can't see a better way to factor this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh that's a very good point that hadn't occurred to me. I will give it some thought, as we definitely need to do some kind of refactoring based on common traits/flavors. I don't think the code as it exists in this PR is long-term maintainable.
case "FlavorTHole": | ||
return "{?}"; | ||
default: | ||
return undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes me think maybe we should split up flavours in to separate types depending on what kind of NodeBody
they correspond to. This would make a few things more elegant. See e.g. the comment about assigning a text colour for FlavorPattern
being "meaningless".
Of course, this change would have to be made in the backend.
@@ -454,8 +621,6 @@ const convertTree = ( | |||
source: id, | |||
target, | |||
className: flavorEdgeClasses(tree.flavor), | |||
// We draw edges above nodes, so that they aren't hidden by nodes' solid backgrounds. | |||
zIndex: 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is because we've dropped the solid background for pattern boxes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More like I dropped the solid background because I couldn't get this to work at all with Tailwind's own z-N
classes. I'm not sure what was going on, but I could not get edges to show up inside pattern boxes, even if I bumped edges' Z-index to the highest value in the hierarchy.
We can revisit this later, but personally I don't mind that there's no background inside the pattern boxes, and I'm not sure we'll want to keep the dotted background in the long run, either, so maybe it won't matter.
const primerNodeTypeName = "primer"; | ||
|
||
type PrimerNodePropsNode = { | ||
label?: string; | ||
contents?: string; | ||
contents: string | undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fact that these aren't trivially interchangeable is one of my two pet hates with TypeScript...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think maybe this is due to strictNullChecks
or another related TypeScript config setting?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, strictNullChecks
would work around it, but it's a very big hammer.
There is a long-open proposal about improving the situation. I think the difficulty comes from the fact that they are distinguishable at runtime, e.g. by using Object.keys
.
Maybe. I think we need to clarify what we mean by "syntax nodes". Certainly, I think we should make it more obvious which nodes are not selectable, which is currently just applications and constructors in patterns (and |
Yeah, I've already got a bit of a list. For one thing, and I mention this now since it's one of the major changes in this PR, I feel quite strongly that syntax nodes shouldn't have the extra text on them. i.e. we should return Anyway, let's save this for a future discussion. |
Yeah we shouldn't get into it here, but personally I feel completely the opposite: most names like But syntax like So despite the fact that they clutter the tree, I think the words are going to be really helpful to beginning students: they see tldr; I think we should only show |
That sounds like a good compromise. |
This series of commits attempts to bring our current tree implementation closer to the UI design spec.