Skip to content

Commit

Permalink
Add optional header to bubble, include "Feedback" for review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
thsparks committed Sep 26, 2024
1 parent 7b252bd commit e5e9c98
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 6 deletions.
10 changes: 6 additions & 4 deletions pxtblocks/plugins/comments/blockComment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ export class CommentIcon extends Blockly.icons.Icon {
*/
protected weight = 3;

protected elementName: string = "comment";
protected xOffsetFieldName = COMMENT_OFFSET_X_FIELD_NAME;
protected yOffsetFieldName = COMMENT_OFFSET_Y_FIELD_NAME;
protected bubbleClasses: string[] = [];
protected bubbleHeaderText: string = undefined;

/** The bubble used to show editable text to the user. */
protected textInputBubble: TextInputBubble | null = null;
Expand Down Expand Up @@ -175,7 +175,7 @@ export class CommentIcon extends Blockly.icons.Icon {
eventUtils.fire(
new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
this.sourceBlock,
this.elementName,
"comment",
null,
oldText,
text,
Expand Down Expand Up @@ -253,7 +253,7 @@ export class CommentIcon extends Blockly.icons.Icon {
eventUtils.fire(
new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
this.sourceBlock,
this.elementName,
"comment",
null,
this.text,
newText,
Expand Down Expand Up @@ -315,7 +315,7 @@ export class CommentIcon extends Blockly.icons.Icon {
new (eventUtils.get(eventUtils.BUBBLE_OPEN))(
this.sourceBlock,
visible,
this.elementName,
"comment",
),
);
}
Expand All @@ -333,6 +333,7 @@ export class CommentIcon extends Blockly.icons.Icon {
this.getBubbleOwnerRect(),
false,
this.bubbleClasses,
this.bubbleHeaderText,
);
this.textInputBubble.setText(this.getText());
this.textInputBubble.setSize(this.bubbleSize, true);
Expand Down Expand Up @@ -362,6 +363,7 @@ export class CommentIcon extends Blockly.icons.Icon {
this.getBubbleOwnerRect(),
true,
this.bubbleClasses,
this.bubbleHeaderText,
);
this.textInputBubble.setText(this.getText());
this.textInputBubble.setSize(this.bubbleSize, true);
Expand Down
44 changes: 43 additions & 1 deletion pxtblocks/plugins/comments/bubble.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as Blockly from "blockly";

import dom = Blockly.utils.dom;
import { setHsvSaturation } from "blockly/core/utils/colour";

/**
* The abstract pop-up bubble class. This creates a UI that looks like a speech
Expand Down Expand Up @@ -56,6 +57,8 @@ export abstract class Bubble implements Blockly.IDeletable {

private topBar: SVGRectElement;

protected header: SVGTextElement;

protected deleteIcon: SVGImageElement;

private collapseIcon: SVGImageElement;
Expand All @@ -76,6 +79,7 @@ export abstract class Bubble implements Blockly.IDeletable {
public readonly workspace: Blockly.WorkspaceSvg,
protected anchor: Blockly.utils.Coordinate,
protected ownerRect?: Blockly.utils.Rect,
protected headerText?: string,
) {
this.id = Blockly.utils.idGenerator.getNextUniqueId();
this.svgRoot = dom.createSvgElement(
Expand Down Expand Up @@ -121,6 +125,17 @@ export abstract class Bubble implements Blockly.IDeletable {
embossGroup
);

if (this.headerText) {
this.header = dom.createSvgElement(
Blockly.utils.Svg.TEXT,
{
'class': 'blocklyText bubbleHeaderText'
},
embossGroup
);
this.header.textContent = this.headerText;
}

this.deleteIcon = dom.createSvgElement(
Blockly.utils.Svg.IMAGE,
{
Expand Down Expand Up @@ -227,6 +242,7 @@ export abstract class Bubble implements Blockly.IDeletable {
const topBarSize = this.topBar.getBBox();
const deleteSize = this.deleteIcon.getBBox();
const foldoutSize = this.collapseIcon.getBBox();
const headerSize = this.header?.getBBox();

size.width = Math.max(size.width, Bubble.MIN_SIZE);
size.height = Math.max(size.height, Bubble.MIN_SIZE);
Expand All @@ -239,6 +255,9 @@ export abstract class Bubble implements Blockly.IDeletable {

this.updateDeleteIconPosition(size, topBarSize, deleteSize);
this.updateFoldoutIconPosition(topBarSize, foldoutSize);
if (headerSize) {
this.updateHeaderPosition(topBarSize, foldoutSize, deleteSize, headerSize);
}

if (relayout) {
this.positionByRect(this.ownerRect);
Expand Down Expand Up @@ -701,6 +720,25 @@ export abstract class Bubble implements Blockly.IDeletable {
this.collapseIcon.setAttribute('x', `${foldoutMargin}`);
}

private updateHeaderPosition(topBarSize: Blockly.utils.Size, foldoutSize: Blockly.utils.Size, deleteSize: Blockly.utils.Size, headerSize: Blockly.utils.Size) {
const foldoutMargin = this.calcFoldoutMargin(topBarSize, foldoutSize);
const deleteMargin = this.calcDeleteMargin(topBarSize, deleteSize);

// Position right of the foldout icon.
// Note, the y position is relative to the bottom of the text.
const xPos = foldoutSize.width + foldoutMargin + Bubble.BORDER_WIDTH;
const yPos = topBarSize.height - headerSize.height / 2 + Bubble.BORDER_WIDTH + 1.5 /* 1.5 is hackathon nudge to get this thing centered */;

// foldoutMargin intentionally included twice (once for left of icon, once for right)
if (topBarSize.width > xPos + foldoutMargin + headerSize.width + deleteSize.width + deleteMargin) {
this.header?.setAttribute('visibility', 'visibile');
this.header?.setAttribute('y', `${yPos}`);
this.header?.setAttribute('x', `${xPos}`);
} else {
this.header?.setAttribute('visibility', 'collapse');
}
}

/** Calculates the margin that should exist around the delete icon. */
private calcDeleteMargin(topBarSize: Blockly.utils.Size, deleteSize: Blockly.utils.Size) {
return ((topBarSize.height - deleteSize.height) / 2) + Bubble.BORDER_WIDTH;
Expand All @@ -720,4 +758,8 @@ Blockly.Css.register(`
.blocklyBubble .blocklyTextarea.blocklyText {
color: #575E75;
}
`);
.blocklyText.bubbleHeaderText {
font-weight: bold;
}
`);
1 change: 1 addition & 0 deletions pxtblocks/plugins/comments/reviewCommentIcon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class ReviewCommentIcon extends CommentIcon {
protected xOffsetFieldName = REVIEW_COMMENT_OFFSET_X_FIELD_NAME;
protected yOffsetFieldName = REVIEW_COMMENT_OFFSET_Y_FIELD_NAME;
protected bubbleClasses = ["reviewCommentBubble"];
protected bubbleHeaderText = lf("Feedback");

constructor(protected readonly sourceBlock: Blockly.Block) {
super(sourceBlock);
Expand Down
3 changes: 2 additions & 1 deletion pxtblocks/plugins/comments/textinput_bubble.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ export class TextInputBubble extends Bubble {
protected ownerRect?: Blockly.utils.Rect,
protected readonly readOnly?: boolean,
protected readonly additionalClasses?: string[],
protected headerText?: string,
) {
super(workspace, anchor, ownerRect);
super(workspace, anchor, ownerRect, headerText);
dom.addClass(this.svgRoot, 'blocklyTextInputBubble');
if (additionalClasses?.length) {
additionalClasses.forEach((c) => dom.addClass(this.svgRoot, c));
Expand Down

0 comments on commit e5e9c98

Please sign in to comment.