Skip to content

Commit

Permalink
Merge pull request #127 from alopezlago/alopezlago/public_1_2_3
Browse files Browse the repository at this point in the history
Merged PR 220: v 1.2.3 - Pronunciation guides in bonuses
  • Loading branch information
alopezlago authored Nov 7, 2021
2 parents d98fcda + fbe2208 commit ee83611
Show file tree
Hide file tree
Showing 12 changed files with 181 additions and 33 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ To use MODAQ in your product as an npm package, do the following

4. If you want to use the packet parser (instead of passing in a packet parameter), you need to include a URL to YAPP

To see what each prop does, visit [this page](https://github.com/alopezlago/QuizBowlDiscordScoreTracker/wiki/ModaqControl-props).

# Getting Started

You will need to have [npm](https://www.npmjs.com/get-npm) and [yarn](https://yarnpkg.com/getting-started/install) installed on your system.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "modaq",
"version": "1.2.2",
"version": "1.2.3",
"description": "Quiz Bowl Reader using TypeScript, React, and MobX",
"repository": {
"type": "git",
Expand Down
4 changes: 2 additions & 2 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: false,
historyApiFallback: true,
}).listen(8080, "localhost.qbreader", function (err, result) {
}).listen(8080, "localhost.quizbowlreader.com", function (err, result) {
if (err) {
console.log(err);
}

console.log("Listening at localhost.qbreader:8080");
console.log("Listening at localhost.quizbowlreader.com:8080");
});
7 changes: 5 additions & 2 deletions src/components/BonusQuestion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from "react";
import { observer } from "mobx-react-lite";
import { mergeStyleSets } from "@fluentui/react";

import * as FormattedTextParser from "src/parser/FormattedTextParser";
import * as PacketState from "../state/PacketState";
import { BonusQuestionPart } from "./BonusQuestionPart";
import { Bonus } from "src/state/PacketState";
import { Cycle } from "src/state/Cycle";
Expand All @@ -22,7 +22,10 @@ export const BonusQuestion = observer((props: IBonusQuestionProps) => {
const throwOutClickHandler: () => void = React.useCallback(() => {
props.cycle.addThrownOutBonus(props.bonusIndex);
}, [props]);
const formattedLeadin: IFormattedText[] = FormattedTextParser.parseFormattedText(props.bonus.leadin.trim());
const formattedLeadin: IFormattedText[] = React.useMemo(
() => PacketState.getBonusWords(props.bonus.leadin, props.appState.game.gameFormat),
[props.bonus.leadin, props.appState.game.gameFormat]
);

const parts: JSX.Element[] = props.bonus.parts.map((bonusPartProps, index) => {
return (
Expand Down
7 changes: 5 additions & 2 deletions src/components/BonusQuestionPart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";
import { Checkbox, Dropdown, IDropdownOption, IDropdownStyles, mergeStyleSets } from "@fluentui/react";
import { observer } from "mobx-react-lite";

import * as FormattedTextParser from "src/parser/FormattedTextParser";
import * as PacketState from "src/state/PacketState";
import { BonusPart } from "src/state/PacketState";
import { Cycle } from "src/state/Cycle";
import { Answer } from "./Answer";
Expand Down Expand Up @@ -66,7 +66,10 @@ export const BonusQuestionPart = observer((props: IBonusQuestionPartProps) => {
);
}

const bonusPartText: IFormattedText[] = FormattedTextParser.parseFormattedText(props.bonusPart.question);
const bonusPartText: IFormattedText[] = React.useMemo(
() => PacketState.getBonusWords(props.bonusPart.question, props.gameFormat),
[props.bonusPart.question, props.gameFormat]
);

// TODO: We should try to resize the checkbox's box to match the font size
return (
Expand Down
11 changes: 10 additions & 1 deletion src/components/FormattedText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const FormattedText = observer(
const classes: IFormattedTextClassNames = useStyles();
const elements: JSX.Element[] = [];
for (let i = 0; i < props.segments.length; i++) {
elements.push(<FormattedSegment key={`segment_${i}`} segment={props.segments[i]} />);
elements.push(<FormattedSegment key={`segment_${i}`} classNames={classes} segment={props.segments[i]} />);
}

const className: string = props.className ? `${classes.text} ${props.className}` : classes.text;
Expand Down Expand Up @@ -42,6 +42,10 @@ const FormattedSegment = observer((props: IFormattedSegmentProps) => {
);
}

if (props.segment.pronunciation) {
element = <span className={props.classNames.pronunciationGuide}>{element}</span>;
}

return element;
});

Expand All @@ -52,10 +56,12 @@ export interface IFormattedTextProps {

interface IFormattedSegmentProps {
segment: IFormattedText;
classNames: IFormattedTextClassNames;
}

interface IFormattedTextClassNames {
text: string;
pronunciationGuide: string;
}

const useStyles = memoizeFunction(
Expand All @@ -64,5 +70,8 @@ const useStyles = memoizeFunction(
text: {
display: "inline",
},
pronunciationGuide: {
color: "rgb(128, 128, 128)",
},
})
);
13 changes: 1 addition & 12 deletions src/components/QuestionWord.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,7 @@ import { FormattedText } from "./FormattedText";

export const QuestionWord = observer(
(props: IQuestionWordProps): JSX.Element => {
const classes = getClassNames(
props.selected,
props.correct,
props.wrong,
props.inPronunciationGuide,
props.index != undefined
);
const classes = getClassNames(props.selected, props.correct, props.wrong, props.index != undefined);

return (
<span ref={props.componentRef} data-index={props.index} className={classes.word}>
Expand All @@ -26,7 +20,6 @@ export const QuestionWord = observer(
interface IQuestionWordProps {
word: IFormattedText[];
index: number | undefined;
inPronunciationGuide?: boolean;
selected?: boolean;
correct?: boolean;
wrong?: boolean;
Expand All @@ -44,7 +37,6 @@ const getClassNames = memoizeFunction(
selected: boolean | undefined,
correct: boolean | undefined,
wrong: boolean | undefined,
isPronunciation: boolean | undefined,
isIndexDefined: boolean
): IQuestionWordClassNames =>
mergeStyleSets({
Expand All @@ -67,9 +59,6 @@ const getClassNames = memoizeFunction(
background: "rgba(128, 128, 128, 0.2)",
textDecoration: "underline double",
},
isPronunciation && {
color: "rgb(128, 128, 128)",
},
// Only highlight a word on hover if it's not in an existing state from selected/correct/wrong
isIndexDefined &&
!(selected || correct || wrong) && { "&:hover": { background: "rgba(200, 200, 0, 0.15)" } },
Expand Down
3 changes: 0 additions & 3 deletions src/components/TossupQuestion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export const TossupQuestion = observer(
correctBuzzIndex={correctBuzzIndex}
index={word.canBuzzOn ? word.wordIndex : undefined}
isLastWord={word.canBuzzOn && word.isLastWord}
inPronunciationGuide={!word.canBuzzOn && word.inPronunciationGuide}
selectedWordRef={selectedWordRef}
word={word.word}
wrongBuzzIndexes={wrongBuzzIndexes}
Expand Down Expand Up @@ -112,7 +111,6 @@ const QuestionWordWrapper = observer((props: IQuestionWordWrapperProps) => {
index={props.index}
word={props.word}
selected={props.index === uiState.selectedWordIndex}
inPronunciationGuide={props.inPronunciationGuide}
correct={props.index === props.correctBuzzIndex}
wrong={props.wrongBuzzIndexes.findIndex((position) => position === props.index) >= 0}
componentRef={selected ? props.selectedWordRef : undefined}
Expand Down Expand Up @@ -170,7 +168,6 @@ interface IQuestionWordWrapperProps {
cycle: Cycle;
index?: number;
isLastWord: boolean;
inPronunciationGuide: boolean;
selectedWordRef: React.MutableRefObject<null>;
tossup: Tossup;
tossupNumber: number;
Expand Down
1 change: 1 addition & 0 deletions src/parser/IFormattedText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export interface IFormattedText {
text: string;
bolded: boolean;
emphasized: boolean;
pronunciation?: boolean;
required?: boolean;
underlined?: boolean;
}
2 changes: 0 additions & 2 deletions src/state/IPacket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ export interface IPacket {
export interface ITossup {
question: string;
answer: string;
number: number;
}

export interface IBonus {
leadin: string;
parts: string[];
answers: string[];
number: number;
values: number[];
difficultyModifiers?: string[];
}
52 changes: 45 additions & 7 deletions src/state/PacketState.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { observable, makeObservable, makeAutoObservable } from "mobx";
import { makeAutoObservable } from "mobx";
import { format } from "mobx-sync";

import * as FormattedTextParser from "src/parser/FormattedTextParser";
Expand Down Expand Up @@ -169,11 +169,14 @@ export class Tossup implements IQuestion {
canBuzzOn,
});
} else {
for (const segment of word) {
segment.pronunciation = !canBuzzOn && inPronunciationGuide;
}

words.push({
nonWordIndex: index,
textIndex: i,
word,
inPronunciationGuide,
canBuzzOn,
});
}
Expand All @@ -198,15 +201,51 @@ export class Bonus {

constructor(leadin: string, parts: BonusPart[]) {
// We don't use makeAutoObservable because leadin doesn't need to be observable (never changes)
makeObservable(this, {
parts: observable,
});
makeAutoObservable(this);

this.leadin = leadin;
this.leadin = leadin.trim();
this.parts = parts;
}
}

export function getBonusWords(text: string, format: IGameFormat): IFormattedText[] {
if (
format.pronunciationGuideMarkers == undefined ||
format.pronunciationGuideMarkers.length !== 2 ||
format.pronunciationGuideMarkers.some((guide) => guide == undefined)
) {
return FormattedTextParser.parseFormattedText(text);
}

const formattedText: IFormattedText[][] = FormattedTextParser.splitFormattedTextIntoWords(text);

const pronunciationGuideMarkers: [string, string] = format.pronunciationGuideMarkers;
let inPronunciationGuide = false;
for (let i = 0; i < formattedText.length; i++) {
const word: IFormattedText[] = formattedText[i];
const fullText = word.reduce((result, text) => result + text.text, "");

if (fullText.startsWith(pronunciationGuideMarkers[0])) {
inPronunciationGuide = true;
}

for (const segment of word) {
segment.pronunciation = inPronunciationGuide;
}

if (inPronunciationGuide && fullText.indexOf(pronunciationGuideMarkers[1]) >= 0) {
inPronunciationGuide = false;
}

// Add the space back to all but the last word
if (i !== formattedText.length - 1) {
word[word.length - 1].text += " ";
}
}

return formattedText.reduce((previous, next) => previous.concat(next), []);
}

export type ITossupWord = IBuzzableTossupWord | INonbuzzableTossupWord;

export interface IBuzzableTossupWord extends IBaseTossupWord {
Expand All @@ -217,7 +256,6 @@ export interface IBuzzableTossupWord extends IBaseTossupWord {

export interface INonbuzzableTossupWord extends IBaseTossupWord {
nonWordIndex: number;
inPronunciationGuide: boolean;
canBuzzOn: false;
}

Expand Down
Loading

0 comments on commit ee83611

Please sign in to comment.