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

Design updates #1542

Merged
merged 9 commits into from
Aug 22, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/chilled-moose-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@khanacademy/perseus": minor
"@khanacademy/perseus-editor": minor
---

Design update for PhET widget
7 changes: 3 additions & 4 deletions packages/perseus/src/widgets/__tests__/phet-sim.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,9 @@ describe("phet-sim widget", () => {

// Assert
await waitFor(() => {
expect(screen.queryByTitle("Google")).toHaveAttribute(
"srcDoc",
"Sorry, this simulation cannot load.",
);
expect(
screen.getByText("Sorry, this simulation cannot load."),
).toBeDefined();
});
});

Expand Down
89 changes: 64 additions & 25 deletions packages/perseus/src/widgets/phet-sim.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@
import {View} from "@khanacademy/wonder-blocks-core";
import IconButton from "@khanacademy/wonder-blocks-icon-button";
import cornersOutIcon from "@phosphor-icons/core/regular/corners-out.svg";
import {StyleSheet} from "aphrodite";
import * as React from "react";

import {PerseusI18nContext} from "../components/i18n-context";
import {getDependencies} from "../dependencies";
import * as Changeable from "../mixins/changeable";
import {phoneMargin} from "../styles/constants";
import {basicBorderColor, borderRadiusLarge} from "../styles/global-constants";

import type {PerseusPhetSimWidgetOptions} from "../perseus-types";
import type {WidgetExports, WidgetProps} from "../types";
Expand All @@ -25,7 +28,10 @@
type UserInput = null;

type State = {
bannerMessage: string | null;
banner: {
message: string;
kind: "warning" | "critical";
} | null;
url: URL | null;
};

Expand All @@ -39,7 +45,7 @@

state: State = {
url: null,
bannerMessage: null,
banner: null,

Check warning on line 48 in packages/perseus/src/widgets/phet-sim.tsx

View check run for this annotation

Codecov / codecov/patch

packages/perseus/src/widgets/phet-sim.tsx#L48

Added line #L48 was not covered by tests
};

constructor(props) {
Expand Down Expand Up @@ -69,29 +75,32 @@
// http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
const sandboxProperties = "allow-same-origin allow-scripts";
return (
<View>
{this.state.bannerMessage && (
<View style={styles.container}>
{this.state.banner !== null && (
// TODO(anna): Make this banner focusable
<Banner
kind="warning"
layout="floating"
text={this.state.bannerMessage}
/>
<View
style={{
marginBottom: phoneMargin,
}}
>
<Banner
layout="floating"
kind={this.state.banner.kind}
text={this.state.banner.message}
/>
</View>
)}
<iframe
ref={this.iframeRef}
title={this.props.description}
sandbox={sandboxProperties}
style={{
width: 400,
height: 400,
minWidth: 400,
height: 360,
width: "100%",
borderWidth: 0,
}}
src={this.state.url?.toString()}
srcDoc={
this.state.url !== null
? undefined
: this.context.strings.simulationLoadFail
}
allow="fullscreen"
/>
<IconButton
Expand All @@ -106,6 +115,7 @@
marginBottom: 5,
alignSelf: "flex-end",
}}
disabled={this.state.url === null}
/>
</View>
);
Expand Down Expand Up @@ -140,22 +150,35 @@
}
};

displayLoadFailure: () => void = () => {
this.setState({
url: null,
banner: {
message: this.context.strings.simulationLoadFail,
kind: "critical",
},
});
};

Check warning on line 162 in packages/perseus/src/widgets/phet-sim.tsx

View check run for this annotation

Codecov / codecov/patch

packages/perseus/src/widgets/phet-sim.tsx#L161-L162

Added lines #L161 - L162 were not covered by tests
async updateSimState(urlString: string) {
const url = makeSafeUrl(urlString, this.locale);
if (url === null) {
this.setState({url: null, bannerMessage: null});
this.displayLoadFailure();
return;
}
const response = await fetch(url);
if (!response.ok) {
this.setState({url: null, bannerMessage: null});
this.displayLoadFailure();

Check warning on line 171 in packages/perseus/src/widgets/phet-sim.tsx

View check run for this annotation

Codecov / codecov/patch

packages/perseus/src/widgets/phet-sim.tsx#L171

Added line #L171 was not covered by tests
return;
}
const showLocaleWarning = await this.showLocaleWarning(url);
this.setState({
url: url,
bannerMessage: showLocaleWarning
? this.context.strings.simulationLocaleWarning
banner: showLocaleWarning
? {
message: this.context.strings.simulationLocaleWarning,
kind: "warning",
}

Check warning on line 181 in packages/perseus/src/widgets/phet-sim.tsx

View check run for this annotation

Codecov / codecov/patch

packages/perseus/src/widgets/phet-sim.tsx#L178-L181

Added lines #L178 - L181 were not covered by tests
: null,
});
}
Expand All @@ -170,7 +193,7 @@
/https:\/\/phet\.colorado\.edu\/sims\/html\/([a-zA-Z0-9-]+)\/.*/g;
const match: RegExpExecArray | null = phetRegex.exec(url.toString());
// Do not show a locale warning on a non-simulation URL
if (!match) {
if (match === null) {
return false;
}
const simName = match[1];
Expand All @@ -180,14 +203,19 @@
if (!response.ok) {
return false;
}
const responseJson = await response.json();
if (!responseJson) {

let responseJson: any;
try {
responseJson = await response.json();
} catch {
// If the file exists but there is no content to parse into a JSON,
// response.json() will throw an error that we want to catch.

Check warning on line 212 in packages/perseus/src/widgets/phet-sim.tsx

View check run for this annotation

Codecov / codecov/patch

packages/perseus/src/widgets/phet-sim.tsx#L211-L212

Added lines #L211 - L212 were not covered by tests
return false;
}
const locales = Object.keys(responseJson);
const locales: string[] = Object.keys(responseJson);

// Only display a locale warning if there is no fallback language
const baseLocale = this.locale.split("_")[0];
const baseLocale: string = this.locale.split("_")[0];
for (const l of locales) {
if (baseLocale === l.split("_")[0]) {
return false;
Expand Down Expand Up @@ -218,3 +246,14 @@
hidden: true,
isLintable: true,
} as WidgetExports<typeof PhetSim>;

const styles = StyleSheet.create({
container: {
borderRadius: borderRadiusLarge,
borderWidth: 1,
borderColor: basicBorderColor,
padding: phoneMargin,
paddingBottom: 0,
width: 650,
},
});