Skip to content

Commit

Permalink
Show feedback comments on the sidebar
Browse files Browse the repository at this point in the history
  • Loading branch information
thsparks committed Dec 16, 2024
1 parent 9d9e2ed commit 0c68fb3
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 102 deletions.
78 changes: 71 additions & 7 deletions theme/common.less
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ pre {
overflow: visible;
}

.hasFeedback #maineditor {
right: @feedbackPanelWidth;
}

/* Editor tools */
@editorToolsHeight: 10rem;
@editorToolsCollapsedHeight: 4.7rem;
Expand Down Expand Up @@ -183,16 +187,76 @@ pre {
cursor: pointer;
}

#feedbackNavArea {
margin: auto;
#feedbackPanel {
display: flex;
flex-direction: column;
position: fixed;
top: @mainMenuHeight;
bottom: 4rem;
right: 0;
background-color: @filelistBackgroundColor;
z-index: @filelistZIndex;
font-family: @pageFont !important;
border-left: 2px solid #dadaef;
width: @feedbackPanelWidth;

.feedback-nav-container {
#feedbackNavArea {
margin: auto;
padding: 1rem;
border-bottom: 1px solid #dadaef;
width: 100%;
display: flex;
flex-direction: row;
.feedback-nav-text {
font-size: 1.2rem;
font-weight: 600;
justify-content: center;

.feedback-nav-container {
display: flex;
flex-direction: row;
.feedback-nav-text {
font-size: 1.2rem;
font-weight: 600;
margin: 0.5rem;
display: flex;
justify-content: center;
align-items: center;
}
.feedback-nav-btn {
margin: 0 0.5rem;
padding: 0.2rem;
}
}
}

.feedback-comments-area {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
margin-top: 1rem;
gap: 1rem;
flex-grow: 1;

.feedback-comment-btn {
margin: 0.5rem;
padding: 0;
width: 80%;
height: fit-content;
background-color: #c7f8ff;
border: 1px solid #00b4cc;
color: black;
border-radius: 0;
text-align: start;

.feedback-comment-header {
background-color: #00b4cc;
color: white;
font-weight: bold;
padding: 0.3rem 0.5rem;
}

.feedback-comment-text-area {
padding: 0.5rem;
text-wrap: auto;
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions theme/themes/pxt/globals/site.variables
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@
@sideBarWidthLarge: 28rem;
@simulatorWidth: 23rem;
@simulatorWidthSmall: 20rem;
@feedbackPanelWidth: 20rem;

/*-------------------
Background
Expand Down
4 changes: 4 additions & 0 deletions webapp/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ import { Tour } from "./components/onboarding/Tour";
import { parseTourStepsAsync } from "./onboarding";
import { initGitHubDb } from "./idbworkspace";
import { BlockDefinition, CategoryNameID } from "./toolbox";
import { FeedbackPanel, getBlocksWithFeedback } from "./feedbackPanel";

pxt.blocks.requirePxtBlockly = () => pxtblockly as any;
pxt.blocks.requireBlockly = () => Blockly;
Expand Down Expand Up @@ -5275,6 +5276,7 @@ export class ProjectView
const collapseIconTooltip = this.state.collapseEditorTools ? lf("Show the simulator") : lf("Hide the simulator");
const isApp = cmds.isNativeHost() || pxt.BrowserUtils.isElectron();
const hc = this.getData<boolean>(auth.HIGHCONTRAST)
const hasFeedback = getBlocksWithFeedback(this).length > 0;

let rootClassList = [
"ui",
Expand Down Expand Up @@ -5313,6 +5315,7 @@ export class ProjectView
this.editor == this.textEditor && this.state.errorListState,
'full-abs',
pxt.appTarget.appTheme.embeddedTutorial ? "tutorial-embed" : "",
hasFeedback ? "hasFeedback" : "",
];
this.rootClasses = rootClassList;
const rootClasses = sui.cx(rootClassList);
Expand Down Expand Up @@ -5380,6 +5383,7 @@ export class ProjectView
{showCollapseButton && <sui.Button id='computertogglesim' className={`computer only collapse-button large`} icon={`inverted chevron ${showRightChevron ? 'right' : 'left'}`} title={collapseIconTooltip} onClick={this.toggleSimulatorCollapse} />}
{this.allEditors.map(e => e.displayOuter(editorOffset))}
</div>
{hasFeedback && <FeedbackPanel parent={this} />}
{inHome ? <div id="homescreen" className="full-abs">
<div className="ui home projectsdialog">
<header className="menubar" role="banner">
Expand Down
95 changes: 0 additions & 95 deletions webapp/src/editortoolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -443,9 +443,6 @@ export class EditorToolbar extends data.Component<ISettingsProps, EditorToolbarS
<identity.CloudSaveStatus headerId={header.id} />
</div>
</div>}
<div id="feedbackNavArea" role="menubar" className="ui column items">
<EditorToolbarFeedbackNav view={this.getViewString(computer)} parent={this.props.parent} />
</div>
<div id="editorToolbarArea" role="menubar" className="ui column items">
{showUndoRedo && <div className="ui icon buttons">{this.getUndoRedo(computer)}</div>}
{showZoomControls && <div className="ui icon buttons mobile hide">{this.getZoomControl(computer)}</div>}
Expand Down Expand Up @@ -661,95 +658,3 @@ class EditorToolbarSaveInput extends React.Component<EditorToolbarSaveInputProps
}
}
}

interface EditorToolbarFeedbackNavProps {
view: string;
parent: pxt.editor.IProjectView;
}
interface EditorToolbarFeedbackNavState {
blocksWithFeedback: Blockly.Block[];
isBlocksActive: boolean;
currentIndex: number;
}
class EditorToolbarFeedbackNav extends React.Component<EditorToolbarFeedbackNavProps, EditorToolbarFeedbackNavState> {
constructor(props: EditorToolbarFeedbackNavProps) {
super(props);

this.state = {
isBlocksActive: this.props.parent.isBlocksActive(),
blocksWithFeedback: [],
currentIndex: 0, // TODO thsparks : This is getting set to NaN for some reason, even with this here??
}
}

protected handlePrevFeedbackClick = () => {
const newIndex = this.state.currentIndex > 0 ? this.state.currentIndex - 1 : this.state.blocksWithFeedback.length - 1;
this.setState({ currentIndex: newIndex });
this.focusOnBlockAtIndex(newIndex);
}

protected handleNextFeedbackClick = () => {
const currentIndex = isNaN(this.state.currentIndex) ? 0 : this.state.currentIndex;
const newIndex = (currentIndex + 1) % this.state.blocksWithFeedback.length;
this.setState({ currentIndex: newIndex });
this.focusOnBlockAtIndex(newIndex);
}

protected focusOnBlockAtIndex(index: number) {
if (!this.props.parent.isBlocksActive()) return;

const block = this.state.blocksWithFeedback[index];
if (block) {
(this.props.parent.editor as blocks.Editor).editor.highlightBlock(block.id);
(this.props.parent.editor as blocks.Editor).editor.centerOnBlock(block.id);

block.getIcon(REVIEW_COMMENT_ICON_TYPE)?.setBubbleVisible(true);
}
}

protected getBlocksWithFeedback(): Blockly.Block[] {
if (!this.props.parent.isBlocksActive()) {
return [];
}

return this.props.parent.getBlocks().map(b => b as Blockly.Block).filter(b => !!ReviewCommentIcon.getReviewCommentForBlock(b));
}

protected updateBlocksWithFeedbackList() {
const blocksWithFeedback = this.getBlocksWithFeedback();
this.setState({ blocksWithFeedback, currentIndex: this.state.currentIndex % blocksWithFeedback.length });
}

componentDidMount() {
this.updateBlocksWithFeedbackList();
}

protected shouldUpdate(): boolean {
if (this.state.isBlocksActive !== this.props.parent.isBlocksActive()) return true;

const newBlocksWithFeedback = this.getBlocksWithFeedback();
if (newBlocksWithFeedback.length !== this.state.blocksWithFeedback.length) return true;
for (const blockId of newBlocksWithFeedback.map(b => b.id)) {
if (!this.state.blocksWithFeedback.find(b => b.id === blockId)) return true;
}

return false;
}

componentDidUpdate(prevProps: EditorToolbarFeedbackNavProps) {
if (this.shouldUpdate()) {
this.updateBlocksWithFeedbackList();

// Save this so we can tell if it changes.
this.setState({ isBlocksActive: this.props.parent.isBlocksActive() });
}
}

render() {
return this.state.blocksWithFeedback?.length ? (<div className="ui feedback-nav-container">
<EditorToolbarButton icon="arrow left" className="editortools-btn" title={lf("Previous Feedback")} onButtonClick={this.handlePrevFeedbackClick} view={this.props.view} />
<div className="feedback-nav-text">{lf("Feedback")}</div>
<EditorToolbarButton icon="arrow right" className="editortools-btn" title={lf("Next Feedback")} onButtonClick={this.handleNextFeedbackClick} view={this.props.view} />
</div>) : null;
}
}
Loading

0 comments on commit 0c68fb3

Please sign in to comment.