= React.createRef();
14 | render() {
15 | return (
16 |
25 |
30 | {
34 | if (this.props.onSendGesture) {
35 | this.props.onSendGesture(true);
36 | }
37 | }}
38 | onMouseUp={() => {
39 | if (this.props.onSendGesture) {
40 | this.props.onSendGesture(false);
41 | }
42 | }}
43 | onKeyDown={this.handleOnKeyDown}
44 | onKeyUp={this.handleOnKeyUp}
45 | type="gesture"
46 | />
47 |
48 | );
49 | }
50 | private handleOnKeyDown = (e: React.KeyboardEvent) => {
51 | if (e.key === CONSTANTS.KEYBOARD_KEYS.ENTER) {
52 | this.sensorButtonRef!.current!.setButtonClass(true);
53 | if (this.props.onSendGesture) {
54 | this.props.onSendGesture(true);
55 | }
56 | }
57 | };
58 |
59 | private handleOnKeyUp = (
60 | e: React.KeyboardEvent,
61 | onSendGesture?: (isActive: boolean) => void
62 | ) => {
63 | if (e.key === CONSTANTS.KEYBOARD_KEYS.ENTER) {
64 | this.sensorButtonRef!.current!.setButtonClass(false);
65 |
66 | if (this.props.onSendGesture) {
67 | this.props.onSendGesture(false);
68 | }
69 | }
70 | };
71 | }
72 |
--------------------------------------------------------------------------------
/src/view/components/toolbar/SensorButton.tsx:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT license.
3 |
4 | import * as React from "react";
5 | import { VIEW_STATE } from "../../constants";
6 | import { ViewStateContext } from "../../context";
7 | import "../../styles/SensorButton.css";
8 | import { ISensorButtonProps } from "../../viewUtils";
9 |
10 | class SensorButton extends React.Component {
11 | private buttonRef: React.RefObject = React.createRef();
12 |
13 | public setButtonClass = (isActive: boolean) => {
14 | const isInputDisabled = this.context === VIEW_STATE.PAUSE;
15 |
16 | if (isActive && !isInputDisabled) {
17 | this.buttonRef.current?.setAttribute(
18 | "class",
19 | "sensor-button active-button"
20 | );
21 | } else if (this.buttonRef.current) {
22 | this.buttonRef!.current!.setAttribute("class", "sensor-button");
23 | }
24 | };
25 | render() {
26 | const isInputDisabled = this.context === VIEW_STATE.PAUSE;
27 |
28 | return (
29 |
42 | );
43 | }
44 | }
45 | SensorButton.contextType = ViewStateContext;
46 | export default SensorButton;
47 |
--------------------------------------------------------------------------------
/src/view/components/toolbar/Toolbar.spec.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as ReactDOM from "react-dom";
3 | import { IntlProvider } from "react-intl";
4 | import * as testRenderer from "react-test-renderer";
5 | import { SENSOR_LIST } from "../../constants";
6 | import * as TOOLBAR_SVG from "../../svgs/toolbar_svg";
7 | import { MICROBIT_TOOLBAR_ICON_ID } from "./SensorModalUtils";
8 | import Toolbar from "./ToolBar";
9 |
10 | const MOCK_TOOLBAR_BUTTONS: Array<{ label: string; image: JSX.Element }> = [
11 | {
12 | image: TOOLBAR_SVG.LIGHT_SVG,
13 | label: MICROBIT_TOOLBAR_ICON_ID.LIGHT,
14 | },
15 | {
16 | image: TOOLBAR_SVG.MOTION_SVG,
17 | label: MICROBIT_TOOLBAR_ICON_ID.ACCELEROMETER,
18 | },
19 | ];
20 | const mockUpdateSensors = () => {
21 | return;
22 | };
23 | const mockInitialValues = {
24 | [SENSOR_LIST.TEMPERATURE]: 0,
25 | [SENSOR_LIST.LIGHT]: 0,
26 | };
27 | describe("Toolbar component ", () => {
28 | it("should render correctly", () => {
29 | const component = testRenderer
30 | .create(
31 |
32 |
37 |
38 | )
39 | .toJSON();
40 | expect(component).toMatchSnapshot();
41 | });
42 |
43 | it("should render without crashing", () => {
44 | const div = document.createElement("div");
45 | ReactDOM.render(
46 |
47 |
52 | ,
53 | div
54 | );
55 | ReactDOM.unmountComponentAtNode(div);
56 | });
57 | });
58 |
--------------------------------------------------------------------------------
/src/view/components/toolbar/cpx/CpxSensorProperties.tsx:
--------------------------------------------------------------------------------
1 | import { SENSOR_LIST } from "../../../constants";
2 | import { ISensorProps, ISliderProps } from "../../../viewUtils";
3 |
4 | const LIGHT_SLIDER_PROPS: ISliderProps = {
5 | maxValue: 320,
6 | minValue: 0,
7 | minLabel: "Dark",
8 | maxLabel: "Bright",
9 | type: "light",
10 | axisLabel: "L",
11 | step: 1,
12 | };
13 |
14 | export const LIGHT_SENSOR_PROPERTIES: ISensorProps = {
15 | LABEL: "Light sensor",
16 | sliderProps: [LIGHT_SLIDER_PROPS],
17 | unitLabel: "Lux",
18 | };
19 |
20 | const TEMPERATURE_SLIDER_PROPS: ISliderProps = {
21 | axisLabel: "T",
22 | maxLabel: "Hot",
23 | maxValue: 125,
24 | minLabel: "Cold",
25 | minValue: -55,
26 | type: SENSOR_LIST.TEMPERATURE,
27 | step: 0.1,
28 | };
29 | export const TEMPERATURE_SENSOR_PROPERTIES: ISensorProps = {
30 | LABEL: "Temperature sensor",
31 | sliderProps: [TEMPERATURE_SLIDER_PROPS],
32 | unitLabel: "°C",
33 | };
34 |
35 | const MOTION_SLIDER_PROPS_X: ISliderProps = {
36 | axisLabel: "X",
37 | maxLabel: "Right",
38 | maxValue: 78,
39 | minLabel: "Left",
40 | minValue: -78,
41 | type: SENSOR_LIST.MOTION_X,
42 | step: 1,
43 | };
44 | const MOTION_SLIDER_PROPS_Y: ISliderProps = {
45 | axisLabel: "Y",
46 | maxLabel: "Front",
47 | maxValue: 78,
48 | minLabel: "Back",
49 | minValue: -78,
50 | type: SENSOR_LIST.MOTION_Y,
51 | step: 1,
52 | };
53 | const MOTION_SLIDER_PROPS_Z: ISliderProps = {
54 | axisLabel: "Z",
55 | maxLabel: "Down",
56 | maxValue: 78,
57 | minLabel: "Up",
58 | minValue: -78,
59 | type: SENSOR_LIST.MOTION_Z,
60 | step: 1,
61 | };
62 |
63 | export const MOTION_SENSOR_PROPERTIES: ISensorProps = {
64 | LABEL: "Motion sensor",
65 | sliderProps: [
66 | MOTION_SLIDER_PROPS_X,
67 | MOTION_SLIDER_PROPS_Y,
68 | MOTION_SLIDER_PROPS_Z,
69 | ],
70 | unitLabel: "Lux",
71 | };
72 |
--------------------------------------------------------------------------------
/src/view/components/toolbar/microbit/MicrobitSensorProperties.tsx:
--------------------------------------------------------------------------------
1 | import { SENSOR_LIST } from "../../../constants";
2 | import { ISensorProps, ISliderProps } from "../../../viewUtils";
3 |
4 | const LIGHT_SLIDER_PROPS: ISliderProps = {
5 | maxValue: 255,
6 | minValue: 0,
7 | minLabel: "Dark",
8 | maxLabel: "Bright",
9 | type: "light",
10 | axisLabel: "L",
11 | step: 1,
12 | };
13 |
14 | export const LIGHT_SENSOR_PROPERTIES: ISensorProps = {
15 | LABEL: "Light sensor",
16 | sliderProps: [LIGHT_SLIDER_PROPS],
17 | unitLabel: "Lux",
18 | };
19 |
20 | const MOTION_SLIDER_PROPS_X: ISliderProps = {
21 | axisLabel: "X",
22 | maxLabel: "Right",
23 | maxValue: 1023,
24 | minLabel: "Left",
25 | minValue: -1023,
26 | type: SENSOR_LIST.MOTION_X,
27 | step: 1,
28 | };
29 |
30 | const MOTION_SLIDER_PROPS_Y: ISliderProps = {
31 | axisLabel: "Y",
32 | maxLabel: "Front",
33 | maxValue: 1023,
34 | minLabel: "Back",
35 | minValue: -1023,
36 | type: SENSOR_LIST.MOTION_Y,
37 | step: 1,
38 | };
39 |
40 | const MOTION_SLIDER_PROPS_Z: ISliderProps = {
41 | axisLabel: "Z",
42 | maxLabel: "Down",
43 | maxValue: 1023,
44 | minLabel: "Up",
45 | minValue: -1023,
46 | type: SENSOR_LIST.MOTION_Z,
47 | step: 1,
48 | };
49 |
50 | export const MOTION_SENSOR_PROPERTIES: ISensorProps = {
51 | LABEL: "Motion sensor",
52 | sliderProps: [
53 | MOTION_SLIDER_PROPS_X,
54 | MOTION_SLIDER_PROPS_Y,
55 | MOTION_SLIDER_PROPS_Z,
56 | ],
57 | unitLabel: "m/s2",
58 | };
59 |
60 | const TEMPERATURE_SLIDER_PROPS: ISliderProps = {
61 | axisLabel: "T",
62 | maxLabel: "Hot",
63 | maxValue: 125,
64 | minLabel: "Cold",
65 | minValue: -55,
66 | type: SENSOR_LIST.TEMPERATURE,
67 | step: 1,
68 | };
69 |
70 | export const TEMPERATURE_SENSOR_PROPERTIES: ISensorProps = {
71 | LABEL: "Temperature sensor",
72 | sliderProps: [TEMPERATURE_SLIDER_PROPS],
73 | unitLabel: "°C",
74 | };
75 |
--------------------------------------------------------------------------------
/src/view/container/device/Device.spec.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as ReactDOM from "react-dom";
3 | import { IntlProvider } from "react-intl";
4 | import * as testRenderer from "react-test-renderer";
5 | import { DEVICE_LIST_KEY } from "../../constants";
6 | import { Device } from "./Device";
7 |
8 | describe("Device component ", () => {
9 | it("should render correctly", () => {
10 | const component = testRenderer
11 | .create(
12 |
13 |
14 |
15 | )
16 | .toJSON();
17 | expect(component).toMatchSnapshot();
18 | });
19 |
20 | it("should render without crashing", () => {
21 | const div = document.createElement("div");
22 | ReactDOM.render(
23 |
24 |
25 | ,
26 | div
27 | );
28 | ReactDOM.unmountComponentAtNode(div);
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/src/view/container/device/Device.tsx:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT license.
3 |
4 | import * as React from "react";
5 | import { Clue } from "../../components/clue/Clue";
6 | import { Cpx } from "../../components/cpx/Cpx";
7 | import { Microbit } from "../../components/microbit/Microbit";
8 | import { DEVICE_LIST_KEY } from "../../constants";
9 |
10 | interface IProps {
11 | currentSelectedDevice: string;
12 | }
13 | // Container to switch between multiple devices
14 |
15 | export class Device extends React.Component {
16 | constructor(props: IProps) {
17 | super(props);
18 | }
19 | render() {
20 | const { currentSelectedDevice } = this.props;
21 |
22 | return (
23 |
24 |
25 | {loadSelectedDevice(currentSelectedDevice)}
26 |
27 |
28 | );
29 | }
30 | }
31 | const loadSelectedDevice = (currentSelectedDevice: string) => {
32 | switch (currentSelectedDevice) {
33 | case DEVICE_LIST_KEY.CPX:
34 | return ;
35 | case DEVICE_LIST_KEY.MICROBIT:
36 | return ;
37 | case DEVICE_LIST_KEY.CLUE:
38 | return ;
39 | default:
40 | return null;
41 | }
42 | };
43 |
--------------------------------------------------------------------------------
/src/view/context.ts:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { VIEW_STATE } from "./constants";
3 |
4 | // View is running by default
5 |
6 | export const ViewStateContext = React.createContext(VIEW_STATE.RUNNING);
7 |
--------------------------------------------------------------------------------
/src/view/index.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css?family=Joti+One");
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: sans-serif;
7 | }
8 |
9 | html,
10 | body {
11 | overflow: hidden;
12 | height: 100%;
13 | }
14 |
--------------------------------------------------------------------------------
/src/view/index.tsx:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation.
2 | // Licensed under the MIT license.
3 |
4 | import * as React from "react";
5 | import * as ReactDOM from "react-dom";
6 | import { IntlProvider } from "react-intl";
7 | import App from "./App";
8 |
9 | import "./index.css";
10 |
11 | const messageEn = require("./translations/en.json");
12 | const locale = "en";
13 |
14 | const message = {
15 | en: messageEn,
16 | };
17 | ReactDOM.render(
18 |
19 |
20 | ,
21 | document.getElementById("root")
22 | );
23 |
--------------------------------------------------------------------------------
/src/view/pages/gettingStarted.css:
--------------------------------------------------------------------------------
1 | .inv {
2 | display: none;
3 | }
4 |
5 | .codeText {
6 | overflow-x: auto;
7 | white-space: pre-wrap;
8 | word-wrap: break-word;
9 | }
10 |
11 | li:not(:last-child) {
12 | margin-bottom: 6px;
13 | }
14 |
15 | .normalFontWeight {
16 | font-weight: normal;
17 | }
18 |
19 | .deviceSelector {
20 | width: 250px;
21 | border: 1px solid var(--vscode-dropdown-border);
22 | background-color: var(--vscode-dropdown-background);
23 | color: var(--vscode-dropdown-foreground);
24 | margin: 0 0 5px;
25 | padding: 8px;
26 | border-radius: 5px;
27 | font-size: 12px;
28 | padding-right: 30px;
29 | }
30 |
31 | .deviceSelector optgroup {
32 | background-color: var(--vscode-dropdown-listBackground);
33 | color: var(--vscode-dropdown-foreground);
34 | }
35 |
36 | .deviceSelector option {
37 | background-color: var(--vscode-dropdown-listBackground);
38 | color: var(--vscode-dropdown-foreground);
39 | }
40 |
41 | .codeBox {
42 | display: block;
43 | width: 90%;
44 | margin: 10px;
45 | padding: 15px;
46 | text-align: left;
47 | background: none;
48 | border: 1px solid grey;
49 | border-radius: 4px;
50 | background-color: var(--vscode-textCodeBlock-background);
51 | }
52 |
53 | .container {
54 | text-align: left;
55 | padding: 0 10px 20px 10px;
56 | }
57 |
--------------------------------------------------------------------------------
/src/view/pages/gettingStarted.spec.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import * as ReactDOM from "react-dom";
3 | import { IntlProvider } from "react-intl";
4 | import * as testRenderer from "react-test-renderer";
5 | import { GettingStartedPage } from "./gettingStarted";
6 |
7 | describe("GettingStartedPage component ", () => {
8 | it("should render correctly", () => {
9 | const component = testRenderer
10 | .create(
11 |
12 |
13 |
14 | )
15 | .toJSON();
16 | expect(component).toMatchSnapshot();
17 | });
18 |
19 | it("should render without crashing", () => {
20 | const div = document.createElement("div");
21 | ReactDOM.render(
22 |
23 |
24 | ,
25 | div
26 | );
27 | ReactDOM.unmountComponentAtNode(div);
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/view/pages/gettingStartedPictures/debugger/debugger_vars.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/vscode-python-devicesimulator/b27b917fc1ac17b9957345ae4a762e3ae05956a6/src/view/pages/gettingStartedPictures/debugger/debugger_vars.png
--------------------------------------------------------------------------------
/src/view/pages/gettingStartedPictures/debugger/debugging.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/vscode-python-devicesimulator/b27b917fc1ac17b9957345ae4a762e3ae05956a6/src/view/pages/gettingStartedPictures/debugger/debugging.gif
--------------------------------------------------------------------------------
/src/view/pages/gettingStartedPictures/debugger/start_debugging.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/vscode-python-devicesimulator/b27b917fc1ac17b9957345ae4a762e3ae05956a6/src/view/pages/gettingStartedPictures/debugger/start_debugging.jpg
--------------------------------------------------------------------------------
/src/view/pages/gettingStartedPictures/debugger/toolbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/vscode-python-devicesimulator/b27b917fc1ac17b9957345ae4a762e3ae05956a6/src/view/pages/gettingStartedPictures/debugger/toolbar.png
--------------------------------------------------------------------------------
/src/view/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/view/styles/Button.css:
--------------------------------------------------------------------------------
1 | .button {
2 | height: 32px;
3 | background: var(--vscode-debugToolBar-background);
4 | border-color: var(--vscode-debugToolBar-background);
5 | }
6 |
7 | .button-icon {
8 | fill: var(--vscode-badgeForegroundOverride);
9 | }
10 |
11 | .button-rectangle {
12 | stroke: var(--vscode-badgeForegroundOverride);
13 | }
14 |
15 | .play-button {
16 | border-radius: 8px 0px 0px 8px;
17 | border-color: var(--vscode-highContrastButtonBorderOverride-color);
18 | }
19 |
20 | .refresh-button {
21 | border-radius: 0px 8px 8px 0px;
22 | border-color: var(--vscode-highContrastButtonBorderOverride-color);
23 | }
24 |
25 | .button:focus,
26 | .button:hover {
27 | background-color: var(--vscode-terminal-selectionBackground);
28 | }
29 |
30 | .button:active {
31 | background-color: var(--vscode-editor-selectionHighlightBackground);
32 | }
33 |
34 | .toolbar-button {
35 | border: none;
36 | }
37 |
38 | .toolbar-button:hover {
39 | outline: none;
40 | }
41 |
42 | .edge-button {
43 | pointer-events: none;
44 | border: none;
45 | }
46 |
47 | .button-pressed {
48 | background-color: var(--vscode-button-background);
49 | outline: none;
50 | }
51 |
--------------------------------------------------------------------------------
/src/view/styles/Dropdown.css:
--------------------------------------------------------------------------------
1 | .dropdown {
2 | background: var(--vscode-debugToolBar-background);
3 | border-color: var(--vscode-foreground);
4 | border-radius: 2px;
5 | box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.22);
6 | color: var(--vscode-foreground);
7 | height: 32px;
8 | width: 100%;
9 | }
10 |
11 | select.dropdown:hover,
12 | select.dropdown:focus,
13 | select.dropdown:active {
14 | outline: 1px solid var(--vscode-button-background);
15 | }
16 |
17 | option {
18 | height: 32px;
19 | background: var(--vscode-debugToolBar-background);
20 | outline: 0;
21 | align-items: center;
22 | font-size: 14px;
23 | color: var(--vscode-foreground);
24 | }
25 |
--------------------------------------------------------------------------------
/src/view/styles/InputSlider.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --slider-gray-color: #cccccc;
3 | --slider-width: 240px;
4 | }
5 | .inputSlider {
6 | height: 48px;
7 | margin-bottom: 60px;
8 | display: table-cell;
9 | }
10 | .sliderValue {
11 | -webkit-appearance: none;
12 | text-align: center;
13 | width: 48px;
14 | height: 32px;
15 | background-color: var(--vscode-editor-background);
16 | margin-right: 15px;
17 | margin-top: auto;
18 | margin-bottom: auto;
19 | margin-left: 5px;
20 | color: var(--badgeForegroundOverride);
21 | border-radius: 2px;
22 | font-size: 16px;
23 | font-weight: bold;
24 | border-width: 1px;
25 | border-radius: 2px;
26 | border-color: var(--vscode-highContrastButtonBorderOverride-color);
27 | }
28 |
29 | .slider {
30 | -webkit-appearance: none;
31 | background-color: var(--slider-gray-color);
32 | height: 1px;
33 | width: var(--slider-width);
34 | vertical-align: middle;
35 | }
36 | .slider::-webkit-slider-thumb {
37 | -webkit-appearance: none;
38 | appearance: none;
39 | width: 16px;
40 | height: 16px;
41 | border-radius: 50%;
42 | background: var(--vscode-textLink-activeForeground);
43 | cursor: pointer;
44 | }
45 |
46 | .slider::-webkit-slider-runnable-track:focus,
47 | .inputSlider:focus,
48 | .slider:focus {
49 | outline: none;
50 | }
51 |
52 | .sliderValue:focus,
53 | .sliderValue:hover {
54 | -webkit-appearance: none;
55 | color: var(--vscode-textLink-activeForeground);
56 | outline: 1px solid var(--vscode-textLink-activeForeground);
57 | }
58 | .maxLabel,
59 | .minLabel {
60 | display: inline-block;
61 | position: absolute;
62 | vertical-align: top;
63 | }
64 |
65 | .maxLabel {
66 | right: 0;
67 | }
68 |
69 | .minLabel {
70 | left: 0;
71 | }
72 |
73 | .sliderArea,
74 | .sliderValue {
75 | display: inline-block;
76 | vertical-align: middle;
77 | }
78 |
79 | .sliderArea {
80 | width: var(--slider-width);
81 | height: 49px;
82 | }
83 | .downLabelArea {
84 | width: var(--slider-width);
85 | height: 15px;
86 | margin-top: 10px;
87 | position: relative;
88 | font-size: 14px;
89 | }
90 | .upLabelArea {
91 | width: var(--slider-width);
92 | height: 15px;
93 | margin-bottom: 10px;
94 | position: relative;
95 | font-weight: bolder;
96 | font-size: 16px;
97 | }
98 |
99 | .slider,
100 | .upLabelArea,
101 | .downLabelArea {
102 | display: block;
103 | }
104 |
--------------------------------------------------------------------------------
/src/view/styles/LightSensorBar.css:
--------------------------------------------------------------------------------
1 | .title {
2 | font-size: 14px;
3 | text-align: left;
4 | font-weight: bold;
5 | }
6 |
7 | .header {
8 | -webkit-appearance: none;
9 | height: 30px;
10 | margin-bottom: 2px;
11 | }
12 |
13 | .lightSensorBar {
14 | -webkit-appearance: none;
15 | margin-top: 10px;
16 | width: 400px;
17 | margin-left: auto;
18 | margin-right: auto;
19 | padding-bottom: 16px;
20 | }
21 |
--------------------------------------------------------------------------------
/src/view/styles/MotionSensorBar.css:
--------------------------------------------------------------------------------
1 | .title {
2 | font-size: 14px;
3 | text-align: left;
4 | }
5 |
6 | .header {
7 | -webkit-appearance: none;
8 | height: 30px;
9 | margin-bottom: 2px;
10 | }
11 |
12 | .MotionSensorBar {
13 | width: 100%;
14 | margin-left: auto;
15 | margin-right: auto;
16 | }
17 |
18 | .sensor-button-container {
19 | padding: 10px 0;
20 | }
21 |
--------------------------------------------------------------------------------
/src/view/styles/SensorButton.css:
--------------------------------------------------------------------------------
1 | .sensor-button {
2 | color: var(--vscode-badgeForegroundOverride);
3 | text-align: center;
4 | background-color: var(--vscode-button-background);
5 | width: 100%;
6 | height: 32px;
7 | font-weight: bolder;
8 | border-color: var(--vscode-highContrastButtonBorderOverride-color);
9 | border-width: 1px;
10 | border-style: solid;
11 | padding: 4px;
12 | }
13 |
14 | .sensor-button:focus,
15 | .sensor-button:active {
16 | outline-width: thick;
17 | outline-offset: 4px;
18 | outline: 2px solid var(--vscode-focusBorder);
19 | background-color: var(--vscode-button-hoverBackground);
20 | }
21 |
22 | .sensor-button:active,
23 | .active-button {
24 | opacity: 0.5;
25 | }
26 |
27 | .sensor-button:hover {
28 | background-color: var(--vscode-button-hoverBackground);
29 | }
30 |
--------------------------------------------------------------------------------
/src/view/styles/Simulator.css:
--------------------------------------------------------------------------------
1 | .simulator {
2 | display: flex;
3 | flex-direction: column;
4 | justify-content: center;
5 | align-items: center;
6 | max-width: 700px;
7 | max-height: 700px;
8 | margin-left: auto;
9 | margin-right: auto;
10 | }
11 |
12 | .buttons {
13 | display: flex;
14 | flex-direction: row;
15 | padding-top: 20px;
16 | justify-content: center;
17 | }
18 |
19 | .file-selector {
20 | padding: 20px;
21 | width: 80%;
22 | height: 30px;
23 | border: 1px solid var(--vscode-debugToolBar-background);
24 | border-radius: 3px;
25 | }
26 |
27 | .shake-pressed {
28 | /* Start the shake animation and make the animation last for 0.5 seconds */
29 | animation: shake 0.5s;
30 |
31 | /* When the animation is finished, start again */
32 | animation-iteration-count: infinite;
33 | }
34 |
35 | @keyframes shake {
36 | 0% {
37 | transform: translate(1px, 1px) rotate(0deg);
38 | }
39 | 10% {
40 | transform: translate(-1px, -2px) rotate(-1deg);
41 | }
42 | 20% {
43 | transform: translate(-3px, 0px) rotate(1deg);
44 | }
45 | 30% {
46 | transform: translate(3px, 2px) rotate(0deg);
47 | }
48 | 40% {
49 | transform: translate(1px, -1px) rotate(1deg);
50 | }
51 | 50% {
52 | transform: translate(-1px, 2px) rotate(-1deg);
53 | }
54 | 60% {
55 | transform: translate(-3px, 1px) rotate(0deg);
56 | }
57 | 70% {
58 | transform: translate(3px, 1px) rotate(-1deg);
59 | }
60 | 80% {
61 | transform: translate(-1px, -1px) rotate(1deg);
62 | }
63 | 90% {
64 | transform: translate(1px, 2px) rotate(0deg);
65 | }
66 | 100% {
67 | transform: translate(1px, -2px) rotate(-1deg);
68 | }
69 | }
70 |
71 | .microbit-container {
72 | max-width: 350px;
73 | padding: 20px;
74 | }
75 | .clue-container {
76 | width: 100%;
77 | max-width: 500px;
78 | padding: 20px;
79 | }
80 | .cpx-container {
81 | width: 100%;
82 | padding-top: 10px;
83 | }
84 |
--------------------------------------------------------------------------------
/src/view/styles/TemperatureSensorBar.css:
--------------------------------------------------------------------------------
1 | .title {
2 | font-size: 14px;
3 | text-align: left;
4 | font-weight: bold;
5 | }
6 |
7 | .header {
8 | -webkit-appearance: none;
9 | height: 30px;
10 | margin-bottom: 2px;
11 | }
12 | .temperatureSensorBar {
13 | margin-top: 10px;
14 | width: 440px;
15 | margin-left: auto;
16 | margin-right: auto;
17 | padding-bottom: 16px;
18 | }
19 |
--------------------------------------------------------------------------------
/src/view/svgs/arrow_right_svg.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | export const ARROW_RIGHT_SVG = (
4 |
19 | );
20 |
21 | export default ARROW_RIGHT_SVG;
22 |
--------------------------------------------------------------------------------
/src/view/svgs/close_svg.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | export const CLOSE_SVG = (
4 |
24 | );
25 |
26 | export default CLOSE_SVG;
27 |
--------------------------------------------------------------------------------
/src/view/svgs/play_svg.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | export const PLAY_SVG = (
4 |
17 | );
18 |
19 | export default PLAY_SVG;
20 |
--------------------------------------------------------------------------------
/src/view/svgs/refresh_svg.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import "../styles/Button.css";
3 |
4 | export const REFRESH_SVG = (
5 |
19 | );
20 |
21 | export default REFRESH_SVG;
22 |
--------------------------------------------------------------------------------
/src/view/svgs/stop_svg.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | export const STOP_SVG = (
4 |
19 | );
20 |
21 | export default STOP_SVG;
22 |
--------------------------------------------------------------------------------
/src/view/svgs/tag_input_svg.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | export const TAG_INPUT_SVG = (
4 |
25 | );
26 |
27 | export default TAG_INPUT_SVG;
28 |
--------------------------------------------------------------------------------
/src/view/svgs/tag_output_svg.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | export const TAG_OUTPUT_SVG = (
4 |
24 | );
25 |
26 | export default TAG_OUTPUT_SVG;
27 |
--------------------------------------------------------------------------------
/src/view/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "esnext",
4 | "moduleResolution": "node",
5 | "target": "es6",
6 | "outDir": "out",
7 | "lib": ["es6", "dom"],
8 | "jsx": "react",
9 | "sourceMap": true,
10 | "rootDir": "..",
11 | "strict": true,
12 | "noUnusedLocals": true,
13 | "noImplicitReturns": true,
14 | "noFallthroughCasesInSwitch": true,
15 | "experimentalDecorators": true
16 | },
17 | "exclude": ["node_modules"],
18 | "include": ["./index.tsx"]
19 | }
20 |
--------------------------------------------------------------------------------
/src/view/utils/MessageUtils.tsx:
--------------------------------------------------------------------------------
1 | interface vscode {
2 | postMessage(message: any): void;
3 | }
4 |
5 | declare const vscode: vscode;
6 |
7 | export const sendMessage = (
8 | type: string,
9 | state: TState
10 | ) => {
11 | vscode.postMessage({ command: type, text: state });
12 | };
13 |
--------------------------------------------------------------------------------
/src/view/viewUtils.tsx:
--------------------------------------------------------------------------------
1 | import { SENSOR_LIST } from "./constants";
2 |
3 | // Copyright (c) Microsoft Corporation.
4 | // Licensed under the MIT license.
5 | export interface ISliderProps {
6 | minValue: number;
7 | maxValue: number;
8 | maxLabel: string;
9 | minLabel: string;
10 | type: string | SENSOR_LIST;
11 | axisLabel: string;
12 | value?: number;
13 | onUpdateValue?: (sensor: SENSOR_LIST, value: number) => void;
14 | step: number;
15 | }
16 |
17 | export interface ISensorButtonProps {
18 | label: string;
19 | type: string;
20 | onMouseUp?: (event: React.PointerEvent) => void;
21 | onMouseDown?: (event: React.PointerEvent) => void;
22 | onKeyUp?: (event: React.KeyboardEvent) => void;
23 | onKeyDown?: (event: React.KeyboardEvent) => void;
24 | }
25 | export interface ISensorProps {
26 | LABEL: string;
27 | sliderProps: ISliderProps[];
28 | unitLabel: string;
29 | }
30 |
31 | export const X_SLIDER_INDEX = 0;
32 | export const Y_SLIDER_INDEX = 1;
33 | export const Z_SLIDER_INDEX = 2;
34 |
--------------------------------------------------------------------------------
/src/vscode_import.ts:
--------------------------------------------------------------------------------
1 | declare const acquireVsCodeApi;
2 |
3 | const vscode = acquireVsCodeApi();
4 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es6",
5 | "outDir": "out",
6 | "lib": ["es6", "dom"],
7 | "sourceMap": true,
8 | "rootDir": "src",
9 | "jsx": "react",
10 | "alwaysStrict": true
11 | },
12 | "exclude": ["node_modules", ".vscode-test"]
13 | }
14 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": ["node_modules/tslint-microsoft-contrib"],
3 | "extends": [
4 | "tslint:latest",
5 | "tslint-react",
6 | "tslint-config-prettier",
7 | "tslint-react-hooks",
8 | "tslint-microsoft-contrib/latest"
9 | ],
10 | "rules": {
11 | "no-implicit-dependencies": [true, "dev"],
12 | "no-string-throw": true,
13 | "no-unused-expression": true,
14 | "no-duplicate-variable": true,
15 | "no-empty": false,
16 | "no-relative-imports": false,
17 | "max-func-body-length": false,
18 | "curly": true,
19 | "class-name": true,
20 | "triple-equals": true,
21 | "object-literal-sort-keys": true,
22 | "react-hooks-nesting": "error",
23 | "ordered-imports": true,
24 | "import-name": false,
25 | "member-access": false,
26 | "no-console": false,
27 | "jsx-boolean-value": false,
28 | "no-unnecessary-semicolons": false,
29 | "no-http-string": false,
30 | "export-name": false,
31 | "interface-name": false
32 | },
33 | "defaultSeverity": "warning"
34 | }
35 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const tsImportPlugin = require("ts-import-plugin");
3 |
4 | module.exports = {
5 | entry: {
6 | simulator: "./src/view/index.tsx"
7 | },
8 | output: {
9 | path: path.resolve(__dirname, "out"),
10 | filename: "[name].js"
11 | },
12 | devServer: {
13 | historyApiFallback: true
14 | },
15 | devtool: "source-map",
16 | resolve: {
17 | extensions: [".js", ".ts", ".tsx", ".json"]
18 | },
19 | module: {
20 | rules: [
21 | {
22 | test: /\.(ts|tsx)$/,
23 | loader: "ts-loader",
24 | options: {
25 | getCustomTransformers: () => ({
26 | before: [
27 | tsImportPlugin({
28 | libraryName: "antd",
29 | libraryDirectory: "es",
30 | style: true
31 | })
32 | ]
33 | })
34 | }
35 | },
36 | {
37 | test: /\.less$/,
38 | use: [
39 | {
40 | loader: "style-loader"
41 | },
42 | {
43 | loader: "css-loader",
44 | options: {
45 | importLoaders: 1,
46 | sourceMap: true
47 | }
48 | },
49 | {
50 | loader: "less-loader",
51 | options: {
52 | javascriptEnabled: true,
53 | sourceMap: true,
54 | modifyVars: {
55 | "@body-background": "var(--background-color)"
56 | }
57 | }
58 | }
59 | ]
60 | },
61 | {
62 | test: /\.css$/,
63 | use: [
64 | {
65 | loader: "style-loader"
66 | },
67 | {
68 | loader: "css-loader"
69 | }
70 | ]
71 | },
72 | {
73 | test: /\.svg$/,
74 | loader: "svg-inline"
75 | }
76 | ]
77 | }
78 | // When importing a module whose path matches one of the following, just
79 | // assume a corresponding global variable exists and use that instead.
80 | // This is important because it allows us to avoid bundling all of our
81 | // dependencies, which allows browsers to cache those libraries between builds.
82 | // externals: {
83 | // react: "React",
84 | // "react-dom": "ReactDOM"
85 | // }
86 | };
87 |
--------------------------------------------------------------------------------