Skip to content
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

[Dev UI] Display info about background image of current question #1222

Merged
merged 8 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eighty-items-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/perseus": patch
---

Fix @phosphor-icon paths in `explanation` widget
5 changes: 5 additions & 0 deletions .changeset/six-melons-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/perseus-dev-ui": patch
---

✨ Display image background info in Dev UI
1 change: 1 addition & 0 deletions config/test/test.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const pkgMap = fs
};
}, {});

/** @type {import('jest').Config} */
module.exports = {
rootDir: path.join(__dirname, "../../"),
transform: {
Expand Down
100 changes: 99 additions & 1 deletion dev/flipbook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@
import Banner from "@khanacademy/wonder-blocks-banner";
import Button from "@khanacademy/wonder-blocks-button";
import {View} from "@khanacademy/wonder-blocks-core";
import IconButton from "@khanacademy/wonder-blocks-icon-button";
import {Strut} from "@khanacademy/wonder-blocks-layout";
import Link from "@khanacademy/wonder-blocks-link";
import {useTimeout} from "@khanacademy/wonder-blocks-timing";
import {color, spacing} from "@khanacademy/wonder-blocks-tokens";
import Toolbar from "@khanacademy/wonder-blocks-toolbar";
import Tooltip from "@khanacademy/wonder-blocks-tooltip";
import {UnreachableCaseError} from "@khanacademy/wonder-stuff-core";
import cameraSlashIcon from "@phosphor-icons/core/regular/camera-slash.svg";
import graphIcon from "@phosphor-icons/core/regular/graph.svg";
import imageIcon from "@phosphor-icons/core/regular/image.svg";
import * as React from "react";
import {useEffect, useReducer, useRef, useState} from "react";
import {useEffect, useMemo, useReducer, useRef, useState} from "react";

import {Renderer} from "../packages/perseus/src";
import {SvgImage} from "../packages/perseus/src/components";
import {mockStrings} from "../packages/perseus/src/strings";
import {isCorrect} from "../packages/perseus/src/util";
import {trueForAllMafsSupportedGraphTypes} from "../packages/perseus/src/widgets/interactive-graphs/mafs-supported-graph-types";
Expand All @@ -35,7 +42,9 @@ import type {
APIOptions,
PerseusRenderer,
PerseusScore,
PerseusWidget,
} from "../packages/perseus/src";
import type {InteractiveGraphWidget} from "../packages/perseus/src/perseus-types";
import type {PropsFor} from "@khanacademy/wonder-blocks-core";

import "../packages/perseus/src/styles/perseus-renderer.less";
Expand All @@ -50,6 +59,16 @@ grep -rl '"type":"segment"' data/questions/ | xargs cat | pbcopy

const LS_QUESTIONS_KEY = "FLIPBOOK-QUESTIONS-JSON";

function isInteractiveGraph(
widget: PerseusWidget,
): widget is InteractiveGraphWidget {
return widget.type === "interactive-graph";
}

function isGraphieUrl(url: string) {
return url.startsWith("web+graphie://");
}

export function Flipbook() {
const [state, dispatch] = useReducer(flipbookModelReducer, {
questions: "",
Expand All @@ -64,6 +83,15 @@ export function Flipbook() {
const questionsState = state.questions.trim();
const noTextEntered = questionsState === "";

const imageUrls = useMemo<ReadonlyArray<string>>(
() =>
Object.values(question?.widgets ?? {})
.filter(isInteractiveGraph)
.map((w) => w.options.backgroundImage?.url ?? "")
.filter((url) => url.length > 0),
Comment on lines +90 to +91
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty string, null, and undefined are all falsey, so this could be simplified to

Suggested change
.map((w) => w.options.backgroundImage?.url ?? "")
.filter((url) => url.length > 0),
.map((w) => w.options.backgroundImage?.url)
.filter(Boolean),

That might be too much magic, though?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[question],
);

useEffect(() => {
const localStorageQuestions =
localStorage.getItem(LS_QUESTIONS_KEY) || "";
Expand Down Expand Up @@ -130,6 +158,35 @@ export function Flipbook() {
</Button>
</>
}
rightContent={
<View>
{imageUrls?.map((url) => (
<Tooltip
key={url}
placement="right"
content={<GraphiePreview url={url} />}
>
<IconButton
icon={
isGraphieUrl(url)
? graphIcon
: imageIcon
}
/>
</Tooltip>
))}
{(imageUrls?.length ?? 0) === 0 && (
<Tooltip
placement="right"
content={
"This graph does not specify a background image"
}
>
<IconButton icon={cameraSlashIcon} />
</Tooltip>
)}
</View>
}
/>

<Strut size={spacing.small_12} />
Expand Down Expand Up @@ -306,3 +363,44 @@ function Progress(props: ProgressProps) {
</div>
);
}

type GraphiePreviewProps = {url: string};

function GraphiePreview({url}: GraphiePreviewProps) {
return (
<>
<Toolbar
leftContent={
<View style={{display: "flex", flexDirection: "row"}}>
This question uses a
{isGraphieUrl(url) ? (
<Link
href={`http://graphie-to-png.khanacademy.systems?preload=${encodeURIComponent(url)}`}
target="_blank"
style={{
marginLeft: spacing.xxSmall_6,
marginRight: spacing.xxSmall_6,
}}
>
Graphie
</Link>
) : (
" regular image "
)}
background.
</View>
}
rightContent={<></>}
/>
<View
className="framework-perseus"
style={{margin: spacing.medium_16, border: "solid 1px grey"}}
>
<SvgImage
alt={"The background image for this graph question"}
src={url}
/>
</View>
</>
);
}
8 changes: 7 additions & 1 deletion dev/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,16 @@
"@khanacademy/pure-markdown": "^0.3.3",
"@khanacademy/simple-markdown": "^0.11.4",
"@khanacademy/wonder-blocks-banner": "^3.0.41",
"@khanacademy/wonder-blocks-icon": "^4.1.0",
"@khanacademy/wonder-blocks-icon-button": "^5.2.0",
"@khanacademy/wonder-blocks-link": "^6.1.0",
"@khanacademy/wonder-blocks-search-field": "^2.2.9",
"@khanacademy/wonder-blocks-timing": "^4.0.2",
"@khanacademy/wonder-blocks-tokens": "^1.0.0",
"@khanacademy/wonder-blocks-toolbar": "^3.0.30",
"@khanacademy/wonder-stuff-core": "^1.5.2"
"@khanacademy/wonder-blocks-tooltip": "^2.2.1",
"@khanacademy/wonder-stuff-core": "^1.5.2",
"@phosphor-icons/core": "^2.0.2"
},
"devDependencies": {
"vite": "^5.1.0"
Expand Down
4 changes: 2 additions & 2 deletions packages/perseus/src/widgets/explanation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import {linterContextDefault} from "@khanacademy/perseus-linter";
import Button from "@khanacademy/wonder-blocks-button";
import {UniqueIDProvider, View} from "@khanacademy/wonder-blocks-core";
import caretDown from "@phosphor-icons/core/assets/regular/caret-down.svg";
import caretUp from "@phosphor-icons/core/assets/regular/caret-up.svg";
import caretDown from "@phosphor-icons/core/regular/caret-down.svg";
import caretUp from "@phosphor-icons/core/regular/caret-up.svg";
import {StyleSheet} from "aphrodite";
import * as React from "react";
import _ from "underscore";
Expand Down