toolbar/buttons: consolidate buttons
@@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../../../test';
|
||||
import { toggleBluetooth } from '../../../ble/actions';
|
||||
import BluetoothButton from './BluetoothButton';
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('should dispatch action when clicked', () => {
|
||||
const [button, dispatch] = testRender(<BluetoothButton />);
|
||||
|
||||
button.getByRole('button', { name: 'Bluetooth' }).click();
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(toggleBluetooth());
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
import { useI18n } from '@shopify/react-i18n';
|
||||
import React from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { toggleBluetooth } from '../../../ble/actions';
|
||||
import { BleConnectionState } from '../../../ble/reducers';
|
||||
import { BootloaderConnectionState } from '../../../lwp3-bootloader/reducers';
|
||||
import { useSelector } from '../../../reducers';
|
||||
import ActionButton from '../../ActionButton';
|
||||
import connectedIcon from './connected.svg';
|
||||
import disconnectedIcon from './disconnected.svg';
|
||||
import { I18nId } from './i18n';
|
||||
|
||||
const BluetoothButton: React.VFC = () => {
|
||||
const bootloaderConnection = useSelector((s) => s.bootloader.connection);
|
||||
const bleConnection = useSelector((s) => s.ble.connection);
|
||||
|
||||
const isDisconnected =
|
||||
bootloaderConnection === BootloaderConnectionState.Disconnected &&
|
||||
bleConnection === BleConnectionState.Disconnected;
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [i18n] = useI18n();
|
||||
|
||||
return (
|
||||
<ActionButton
|
||||
label={i18n.translate(I18nId.Label)}
|
||||
tooltip={i18n.translate(
|
||||
isDisconnected ? I18nId.TooltipConnect : I18nId.TooltipDisconnect,
|
||||
)}
|
||||
icon={isDisconnected ? disconnectedIcon : connectedIcon}
|
||||
enabled={isDisconnected || bleConnection === BleConnectionState.Connected}
|
||||
showProgress={bleConnection === BleConnectionState.Connecting}
|
||||
onAction={() => dispatch(toggleBluetooth())}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default BluetoothButton;
|
||||
@@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 26.458333 26.458334"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="bt-connected.svg"
|
||||
inkscape:export-filename="button.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96">
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="light-circle-fill"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(1.6201655,0,0,1.6201655,-208.26055,-377.58061)">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5207" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="icon-contents"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.78378378,0,0,0.78378378,-217.21909,-864.32335)">
|
||||
<stop
|
||||
style="stop-color:#3880b7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5179" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-circle-edge"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.04571075,0,0,0.26284445,-63.602396,-483.67016)">
|
||||
<stop
|
||||
style="stop-color:#b7b7b7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5173" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="dark-back"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(1195.9167,-717.54999)">
|
||||
<stop
|
||||
style="stop-color:#333333;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1439" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="dark-front"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(4643.556,-4.2349475e-6)">
|
||||
<stop
|
||||
style="stop-color:#d4d4d4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1389" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-front"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(-313.01005,-269.76128)">
|
||||
<stop
|
||||
style="stop-color:#4e4e4e;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1184" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-back"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(-78.252472)">
|
||||
<stop
|
||||
style="stop-color:#eeeeee;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1172" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#light-circle-fill"
|
||||
id="linearGradient5199"
|
||||
x1="76.890312"
|
||||
y1="96.730286"
|
||||
x2="84.212921"
|
||||
y2="96.730286"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.2728572,0,0,1.2728572,-22.909817,-26.355555)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="16"
|
||||
inkscape:cx="21.730624"
|
||||
inkscape:cy="15.927965"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="g1254"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1853"
|
||||
inkscape:window-height="1145"
|
||||
inkscape:window-x="67"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
units="px"
|
||||
inkscape:measure-start="0,0"
|
||||
inkscape:measure-end="0,0"
|
||||
inkscape:snap-global="false"
|
||||
showguides="true"
|
||||
inkscape:pagecheckerboard="true" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-270.54165)">
|
||||
<g
|
||||
transform="matrix(1.5712682,0,0,1.5712682,-114.96952,131.35809)"
|
||||
id="g1254">
|
||||
<path
|
||||
style="fill:none;stroke:url(#linearGradient5199);stroke-width:1.34710717;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 75.46292,99.915389 7.760721,-6.421198 -3.784681,-3.146812 v 12.778601 l 3.805941,-3.380689 -7.856399,-6.463723"
|
||||
id="path1061"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
<path
|
||||
style="fill:url(#light-circle-fill);fill-opacity:1;stroke:none;stroke-width:1.34710717;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path1063"
|
||||
sodipodi:type="arc"
|
||||
sodipodi:cx="82.457184"
|
||||
sodipodi:cy="96.529022"
|
||||
sodipodi:rx="2.976866"
|
||||
sodipodi:ry="2.976866"
|
||||
sodipodi:start="5.5902437"
|
||||
sodipodi:end="0.68451919"
|
||||
d="m 84.747496,94.627391 a 2.976866,2.976866 0 0 1 0.01593,3.783905 l -2.306247,-1.882274 z"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
<path
|
||||
style="fill:url(#light-circle-fill);fill-opacity:1;stroke:none;stroke-width:1.34710717;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 86.772857,92.884335 -1.068213,0.886672 c 1.320158,1.59269 1.328977,3.896842 0.02105,5.499591 -0.0025,0.0015 -0.0062,-3.05e-4 1.077354,0.884102 1.729557,-2.118935 1.716876,-5.165832 -0.03026,-7.270296 z"
|
||||
id="path1065"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.1 KiB |
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 26.458333 26.458334"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="bt-disconnected.svg"
|
||||
inkscape:export-filename="button.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96">
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="light-circle-fill"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(1.6201655,0,0,1.6201655,-208.26055,-377.58061)">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5207" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="icon-contents"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.78378378,0,0,0.78378378,-217.21909,-864.32335)">
|
||||
<stop
|
||||
style="stop-color:#3880b7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5179" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-circle-edge"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.04571075,0,0,0.26284445,-63.602396,-483.67016)">
|
||||
<stop
|
||||
style="stop-color:#b7b7b7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5173" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="dark-back"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(1195.9167,-717.54999)">
|
||||
<stop
|
||||
style="stop-color:#333333;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1439" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="dark-front"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(4643.556,-4.2349475e-6)">
|
||||
<stop
|
||||
style="stop-color:#d4d4d4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1389" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-front"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(-313.01005,-269.76128)">
|
||||
<stop
|
||||
style="stop-color:#4e4e4e;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1184" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-back"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(-78.252472)">
|
||||
<stop
|
||||
style="stop-color:#eeeeee;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1172" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#light-circle-fill"
|
||||
id="linearGradient5199"
|
||||
x1="76.890312"
|
||||
y1="96.730286"
|
||||
x2="84.212921"
|
||||
y2="96.730286"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.2728572,0,0,1.2728572,-22.909817,-26.355555)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="16"
|
||||
inkscape:cx="30.590127"
|
||||
inkscape:cy="29.036914"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="g1254"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1853"
|
||||
inkscape:window-height="1145"
|
||||
inkscape:window-x="67"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
units="px"
|
||||
inkscape:measure-start="0,0"
|
||||
inkscape:measure-end="0,0"
|
||||
inkscape:snap-global="false"
|
||||
showguides="true"
|
||||
inkscape:pagecheckerboard="true" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-270.54165)">
|
||||
<g
|
||||
transform="matrix(1.5712682,0,0,1.5712682,-114.96952,131.35809)"
|
||||
id="g1254">
|
||||
<path
|
||||
style="fill:none;stroke:url(#linearGradient5199);stroke-width:1.34710717;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 75.46292,99.915389 7.760721,-6.421198 -3.784681,-3.146812 v 12.778601 l 3.805941,-3.380689 -7.856399,-6.463723"
|
||||
id="path1061"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
import { lookup } from '../../../../test';
|
||||
import { I18nId } from './i18n';
|
||||
import en from './translations/en.json';
|
||||
|
||||
describe('Ensure .json file has matches for I18nId', () => {
|
||||
test.each(Object.values(I18nId))('%s', (id) => {
|
||||
expect(lookup(en, id)).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
export enum I18nId {
|
||||
Label = 'label',
|
||||
TooltipConnect = 'tooltip.connect',
|
||||
TooltipDisconnect = 'tooltip.disconnect',
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"label": "Bluetooth",
|
||||
"tooltip": {
|
||||
"connect": "Connect using Bluetooth",
|
||||
"disconnect": "Disconnect Bluetooth"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../../../test';
|
||||
import { flashFirmware } from '../../../firmware/actions';
|
||||
import FlashButton from './FlashButton';
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('should dispatch action when clicked', () => {
|
||||
const [button, dispatch] = testRender(<FlashButton />);
|
||||
|
||||
button.getByRole('button', { name: 'Flash' }).click();
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(flashFirmware(null, false, ''));
|
||||
});
|
||||
@@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
import { useI18n } from '@shopify/react-i18n';
|
||||
import React from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { BleConnectionState } from '../../../ble/reducers';
|
||||
import { flashFirmware } from '../../../firmware/actions';
|
||||
import { BootloaderConnectionState } from '../../../lwp3-bootloader/reducers';
|
||||
import * as notificationActions from '../../../notifications/actions';
|
||||
import { useSelector } from '../../../reducers';
|
||||
import {
|
||||
useSettingFlashCurrentProgram,
|
||||
useSettingHubName,
|
||||
} from '../../../settings/hooks';
|
||||
import OpenFileButton from '../../../toolbar/OpenFileButton';
|
||||
import { I18nId } from './i18n';
|
||||
import icon from './icon.svg';
|
||||
|
||||
const FlashButton: React.VFC = () => {
|
||||
const bootloaderConnection = useSelector((s) => s.bootloader.connection);
|
||||
const bleConnection = useSelector((s) => s.ble.connection);
|
||||
const flashing = useSelector((s) => s.firmware.flashing);
|
||||
const progress = useSelector((s) => s.firmware.progress);
|
||||
const [isSettingFlashCurrentProgramEnabled] = useSettingFlashCurrentProgram();
|
||||
const { hubName } = useSettingHubName();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [i18n] = useI18n();
|
||||
|
||||
return (
|
||||
<OpenFileButton
|
||||
label={i18n.translate(I18nId.Label)}
|
||||
fileExtension=".zip"
|
||||
icon={icon}
|
||||
tooltip={
|
||||
progress
|
||||
? i18n.translate(I18nId.TooltipProgress, {
|
||||
percent: i18n.formatPercentage(progress),
|
||||
})
|
||||
: i18n.translate(I18nId.TooltipAction)
|
||||
}
|
||||
enabled={
|
||||
bootloaderConnection === BootloaderConnectionState.Disconnected &&
|
||||
bleConnection === BleConnectionState.Disconnected
|
||||
}
|
||||
showProgress={flashing}
|
||||
progress={progress === null ? undefined : progress}
|
||||
onFile={(data) =>
|
||||
dispatch(
|
||||
flashFirmware(data, isSettingFlashCurrentProgramEnabled, hubName),
|
||||
)
|
||||
}
|
||||
onReject={(file) =>
|
||||
dispatch(
|
||||
notificationActions.add(
|
||||
'error',
|
||||
`'${file.name}' is not a valid firmware file.`,
|
||||
),
|
||||
)
|
||||
}
|
||||
onClick={() =>
|
||||
dispatch(
|
||||
flashFirmware(null, isSettingFlashCurrentProgramEnabled, hubName),
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default FlashButton;
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
import { lookup } from '../../../../test';
|
||||
import { I18nId } from './i18n';
|
||||
import en from './translations/en.json';
|
||||
|
||||
describe('Ensure .json file has matches for I18nId', () => {
|
||||
test.each(Object.values(I18nId))('%s', (id) => {
|
||||
expect(lookup(en, id)).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
export enum I18nId {
|
||||
Label = 'label',
|
||||
TooltipAction = 'tooltip.action',
|
||||
TooltipProgress = 'tooltip.progress',
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 26.458333 26.458334"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="firmware.svg"
|
||||
inkscape:export-filename="button.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96">
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="light-circle-fill"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.04149181,0,0,0.04149181,1.7417234,549.61437)">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5207" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="icon-contents"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.78378378,0,0,0.78378378,-217.21909,-864.32335)">
|
||||
<stop
|
||||
style="stop-color:#3880b7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5179" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-circle-edge"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.04571075,0,0,0.26284445,-63.602396,-483.67016)">
|
||||
<stop
|
||||
style="stop-color:#b7b7b7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5173" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="dark-back"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(1195.9167,-717.54999)">
|
||||
<stop
|
||||
style="stop-color:#333333;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1439" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="dark-front"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(4643.556,-4.2349475e-6)">
|
||||
<stop
|
||||
style="stop-color:#d4d4d4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1389" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-front"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(-313.01005,-269.76128)">
|
||||
<stop
|
||||
style="stop-color:#4e4e4e;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1184" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-back"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(-78.252472)">
|
||||
<stop
|
||||
style="stop-color:#eeeeee;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1172" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#light-circle-fill"
|
||||
id="linearGradient5187"
|
||||
x1="170.49026"
|
||||
y1="91.974777"
|
||||
x2="171.5486"
|
||||
y2="91.974777"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(2.2770973,0,0,2.2770973,-375.89057,64.428671)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.313708"
|
||||
inkscape:cx="33.439167"
|
||||
inkscape:cy="33.623378"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1853"
|
||||
inkscape:window-height="1145"
|
||||
inkscape:window-x="67"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
units="px"
|
||||
inkscape:measure-start="0,0"
|
||||
inkscape:measure-end="0,0"
|
||||
inkscape:snap-global="false"
|
||||
showguides="true"
|
||||
inkscape:pagecheckerboard="true" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-270.54165)">
|
||||
<path
|
||||
transform="matrix(0,2.2770972,-2.2770972,0,242.26153,191.39198)"
|
||||
sodipodi:type="star"
|
||||
style="fill:url(#light-circle-fill);fill-opacity:1;stroke:none;stroke-width:0.92954594;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path924"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="37.758598"
|
||||
sodipodi:cy="100.44551"
|
||||
sodipodi:r1="1.9985147"
|
||||
sodipodi:r2="0.99925733"
|
||||
sodipodi:arg1="0"
|
||||
sodipodi:arg2="1.0471976"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 39.757113,100.44551 -1.498886,0.86538 -1.498886,0.86539 v -1.73077 -1.730764 l 1.498886,0.865383 z"
|
||||
inkscape:transform-center-y="0.56883747"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:transform-center-x="-5.2936222e-06" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path926"
|
||||
d="m 13.537299,271.92763 v 3.8731"
|
||||
style="fill:#4e4e4e;fill-opacity:1;stroke:url(#linearGradient5187);stroke-width:2.11666656;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
<rect
|
||||
style="fill:url(#light-circle-fill);fill-opacity:1;stroke:none;stroke-width:0.59935653;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect940"
|
||||
width="24.01683"
|
||||
height="10.585944"
|
||||
x="1.2748805"
|
||||
y="284.17142"
|
||||
rx="0"
|
||||
ry="0"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
<rect
|
||||
ry="0"
|
||||
rx="0"
|
||||
y="283.18323"
|
||||
x="3.4314961"
|
||||
height="10.585944"
|
||||
width="2.7715306"
|
||||
id="rect942"
|
||||
style="fill:url(#light-circle-fill);fill-opacity:1;stroke:none;stroke-width:0.20360442;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
<rect
|
||||
style="fill:url(#light-circle-fill);fill-opacity:1;stroke:none;stroke-width:0.20360442;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect944"
|
||||
width="2.7715306"
|
||||
height="10.585944"
|
||||
x="9.0755405"
|
||||
y="283.18323"
|
||||
rx="0"
|
||||
ry="0"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
<rect
|
||||
ry="0"
|
||||
rx="0"
|
||||
y="283.18323"
|
||||
x="14.719461"
|
||||
height="10.585944"
|
||||
width="2.7715306"
|
||||
id="rect947"
|
||||
style="fill:url(#light-circle-fill);fill-opacity:1;stroke:none;stroke-width:0.20360442;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
<rect
|
||||
style="fill:url(#light-circle-fill);fill-opacity:1;stroke:none;stroke-width:0.20360442;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect949"
|
||||
width="2.7715306"
|
||||
height="10.585944"
|
||||
x="20.363565"
|
||||
y="283.18323"
|
||||
rx="0"
|
||||
ry="0"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.7 KiB |
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"label": "Flash",
|
||||
"tooltip": {
|
||||
"action": "Install Pybricks firmware",
|
||||
"progress": "Flashing… {percent}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../../../test';
|
||||
import { repl } from '../../../hub/actions';
|
||||
import { HubRuntimeState } from '../../../hub/reducers';
|
||||
import ReplButton from './ReplButton';
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('should dispatch action when clicked', () => {
|
||||
const [button, dispatch] = testRender(<ReplButton />, {
|
||||
hub: { runtime: HubRuntimeState.Idle },
|
||||
});
|
||||
|
||||
button.getByRole('button', { name: 'REPL' }).click();
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(repl());
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
import { useI18n } from '@shopify/react-i18n';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { repl } from '../../../hub/actions';
|
||||
import { HubRuntimeState } from '../../../hub/reducers';
|
||||
import { useSelector } from '../../../reducers';
|
||||
import ActionButton from '../../ActionButton';
|
||||
import { I18nId } from './i18n';
|
||||
import icon from './icon.svg';
|
||||
|
||||
const ReplButton: React.VFC = () => {
|
||||
const enabled = useSelector((s) => s.hub.runtime === HubRuntimeState.Idle);
|
||||
const [i18n] = useI18n();
|
||||
const dispatch = useDispatch();
|
||||
const action = useCallback(() => dispatch(repl()), [dispatch]);
|
||||
|
||||
return (
|
||||
<ActionButton
|
||||
label={i18n.translate(I18nId.Label)}
|
||||
tooltip={i18n.translate(I18nId.Tooltip)}
|
||||
icon={icon}
|
||||
enabled={enabled}
|
||||
onAction={action}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReplButton;
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
import { lookup } from '../../../../test';
|
||||
import { I18nId } from './i18n';
|
||||
import en from './translations/en.json';
|
||||
|
||||
describe('Ensure .json file has matches for I18nId', () => {
|
||||
test.each(Object.values(I18nId))('%s', (id) => {
|
||||
expect(lookup(en, id)).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
export enum I18nId {
|
||||
Label = 'label',
|
||||
Tooltip = 'tooltip',
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 26.458333 26.458334"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="repl.svg"
|
||||
inkscape:export-filename="button.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96">
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="light-circle-fill"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(-111.65281,-194.6407)">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5207" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="icon-contents"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.78378378,0,0,0.78378378,-217.21909,-864.32335)">
|
||||
<stop
|
||||
style="stop-color:#3880b7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5179" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-circle-edge"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.04571075,0,0,0.26284445,-63.602396,-483.67016)">
|
||||
<stop
|
||||
style="stop-color:#b7b7b7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5173" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="dark-back"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(1195.9167,-717.54999)">
|
||||
<stop
|
||||
style="stop-color:#333333;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1439" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="dark-front"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(4643.556,-4.2349475e-6)">
|
||||
<stop
|
||||
style="stop-color:#d4d4d4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1389" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-front"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(-313.01005,-269.76128)">
|
||||
<stop
|
||||
style="stop-color:#4e4e4e;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1184" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-back"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(-78.252472)">
|
||||
<stop
|
||||
style="stop-color:#eeeeee;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1172" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#light-circle-fill"
|
||||
id="linearGradient5189"
|
||||
x1="151.17233"
|
||||
y1="96.594086"
|
||||
x2="155.53439"
|
||||
y2="96.594086"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(2.4800054,0,0,2.5237898,-359.04545,39.652624)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#light-circle-fill"
|
||||
id="linearGradient5191"
|
||||
x1="147.6288"
|
||||
y1="96.594086"
|
||||
x2="151.99086"
|
||||
y2="96.594086"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(2.4800054,0,0,2.5237898,-358.13592,39.652624)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#light-circle-fill"
|
||||
id="linearGradient5193"
|
||||
x1="144.08528"
|
||||
y1="96.594086"
|
||||
x2="148.44734"
|
||||
y2="96.594086"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(2.4800054,0,0,2.5237898,-357.22644,39.652624)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="16"
|
||||
inkscape:cx="26.727876"
|
||||
inkscape:cy="22.121513"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1853"
|
||||
inkscape:window-height="1145"
|
||||
inkscape:window-x="67"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
units="px"
|
||||
inkscape:measure-start="0,0"
|
||||
inkscape:measure-end="0,0"
|
||||
inkscape:snap-global="false"
|
||||
showguides="true"
|
||||
inkscape:pagecheckerboard="true" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-270.54165)">
|
||||
<path
|
||||
style="fill:none;stroke:url(#linearGradient5193);stroke-width:2.11666656;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 0.93974812,276.85042 7.92259998,6.63441 -7.7594,6.53898"
|
||||
id="path1115"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path1135"
|
||||
d="m 8.8182101,276.85042 7.9225999,6.63441 -7.7593799,6.53898"
|
||||
style="fill:none;stroke:url(#linearGradient5191);stroke-width:2.11666656;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
<path
|
||||
style="fill:none;stroke:url(#linearGradient5189);stroke-width:2.11666656;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 16.696658,276.85042 7.92262,6.63441 -7.7594,6.53898"
|
||||
id="path1137"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.1 KiB |
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"label": "REPL",
|
||||
"tooltip": "Start REPL in terminal"
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../../../test';
|
||||
import { downloadAndRun } from '../../../hub/actions';
|
||||
import { HubRuntimeState } from '../../../hub/reducers';
|
||||
import RunButton from './RunButton';
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('should dispatch action when clicked', () => {
|
||||
const [button, dispatch] = testRender(<RunButton />, {
|
||||
app: { hasEditor: true },
|
||||
hub: { runtime: HubRuntimeState.Idle },
|
||||
});
|
||||
|
||||
button.getByRole('button', { name: 'Run' }).click();
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(downloadAndRun());
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
import { useI18n } from '@shopify/react-i18n';
|
||||
import React from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { downloadAndRun } from '../../../hub/actions';
|
||||
import { HubRuntimeState } from '../../../hub/reducers';
|
||||
import { useSelector } from '../../../reducers';
|
||||
import ActionButton from '../../ActionButton';
|
||||
import { I18nId } from './i18n';
|
||||
import icon from './icon.svg';
|
||||
|
||||
const RunButton: React.VFC = () => {
|
||||
const downloadProgress = useSelector((s) => s.hub.downloadProgress);
|
||||
const runtime = useSelector((s) => s.hub.runtime);
|
||||
const hasEditor = useSelector((s) => s.app.hasEditor);
|
||||
const keyboardShortcut = 'F5';
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [i18n] = useI18n();
|
||||
|
||||
return (
|
||||
<ActionButton
|
||||
label={i18n.translate(I18nId.Label)}
|
||||
keyboardShortcut={keyboardShortcut}
|
||||
tooltip={
|
||||
downloadProgress
|
||||
? i18n.translate(I18nId.TooltipProgress, {
|
||||
percent: i18n.formatPercentage(downloadProgress),
|
||||
})
|
||||
: i18n.translate(I18nId.TooltipAction, { key: keyboardShortcut })
|
||||
}
|
||||
icon={icon}
|
||||
enabled={hasEditor && runtime === HubRuntimeState.Idle}
|
||||
showProgress={runtime === HubRuntimeState.Loading}
|
||||
progress={downloadProgress === null ? undefined : downloadProgress}
|
||||
onAction={() => dispatch(downloadAndRun())}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default RunButton;
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
import { lookup } from '../../../../test';
|
||||
import { I18nId } from './i18n';
|
||||
import en from './translations/en.json';
|
||||
|
||||
describe('Ensure .json file has matches for I18nId', () => {
|
||||
test.each(Object.values(I18nId))('%s', (id) => {
|
||||
expect(lookup(en, id)).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
export enum I18nId {
|
||||
Label = 'label',
|
||||
TooltipAction = 'tooltip.action',
|
||||
TooltipProgress = 'tooltip.progress',
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 26.458333 26.458334"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="run.svg"
|
||||
inkscape:export-filename="button.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96">
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="light-circle-fill"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.52916667,0,0,0.52916667,-54.066878,170.25889)">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5207" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="icon-contents"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.78378378,0,0,0.78378378,-217.21909,-864.32335)">
|
||||
<stop
|
||||
style="stop-color:#3880b7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5179" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-circle-edge"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.04571075,0,0,0.26284445,-63.602396,-483.67016)">
|
||||
<stop
|
||||
style="stop-color:#b7b7b7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5173" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="dark-back"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(1195.9167,-717.54999)">
|
||||
<stop
|
||||
style="stop-color:#333333;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1439" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="dark-front"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(4643.556,-4.2349475e-6)">
|
||||
<stop
|
||||
style="stop-color:#d4d4d4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1389" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-front"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(-313.01005,-269.76128)">
|
||||
<stop
|
||||
style="stop-color:#4e4e4e;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1184" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-back"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(-78.252472)">
|
||||
<stop
|
||||
style="stop-color:#eeeeee;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1172" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="5.6568542"
|
||||
inkscape:cx="32.44435"
|
||||
inkscape:cy="20.159859"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1853"
|
||||
inkscape:window-height="1145"
|
||||
inkscape:window-x="67"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
units="px"
|
||||
inkscape:measure-start="0,0"
|
||||
inkscape:measure-end="0,0"
|
||||
inkscape:snap-global="false"
|
||||
showguides="true"
|
||||
inkscape:pagecheckerboard="true" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-270.54165)">
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:url(#light-circle-fill);fill-opacity:1;stroke:none;stroke-width:2.11666656;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path1017"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="10.839368"
|
||||
sodipodi:cy="283.3425"
|
||||
sodipodi:r1="11.6466"
|
||||
sodipodi:r2="5.8232999"
|
||||
sodipodi:arg1="0"
|
||||
sodipodi:arg2="1.0471976"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 22.485968,283.3425 -8.73495,5.04312 -8.73495,5.04313 0,-10.08625 0,-10.08625 8.73495,5.04312 z"
|
||||
inkscape:transform-center-x="-1.4558184"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"label": "Run",
|
||||
"tooltip": {
|
||||
"action": "Download and run this program ({key})",
|
||||
"progress": "Downloading… {percent}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../../../test';
|
||||
import SettingsButton from './SettingsButton';
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('should invoke callback when clicked', () => {
|
||||
const handleAction = jest.fn();
|
||||
|
||||
const [button] = testRender(<SettingsButton onAction={handleAction} />);
|
||||
|
||||
button.getByRole('button', { name: 'Settings' }).click();
|
||||
|
||||
expect(handleAction).toHaveBeenCalled();
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2021-2022 The Pybricks Authors
|
||||
|
||||
import { useI18n } from '@shopify/react-i18n';
|
||||
import React from 'react';
|
||||
import ActionButton, { ActionButtonProps } from '../../ActionButton';
|
||||
import { I18nId } from './i18n';
|
||||
import icon from './icon.svg';
|
||||
|
||||
type SettingsButtonProps = Pick<ActionButtonProps, 'onAction'>;
|
||||
|
||||
const SettingsButton: React.VoidFunctionComponent<SettingsButtonProps> = ({
|
||||
onAction,
|
||||
}) => {
|
||||
const [i18n] = useI18n();
|
||||
|
||||
return (
|
||||
<ActionButton
|
||||
label={i18n.translate(I18nId.Label)}
|
||||
tooltip={i18n.translate(I18nId.Tooltip)}
|
||||
icon={icon}
|
||||
onAction={onAction}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsButton;
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
import { lookup } from '../../../../test';
|
||||
import { I18nId } from './i18n';
|
||||
import en from './translations/en.json';
|
||||
|
||||
describe('Ensure .json file has matches for I18nId', () => {
|
||||
test.each(Object.values(I18nId))('%s', (id) => {
|
||||
expect(lookup(en, id)).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
export enum I18nId {
|
||||
Label = 'label',
|
||||
Tooltip = 'tooltip',
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 50 50"
|
||||
enable-background="new 0 0 20 20"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="settings.svg"
|
||||
width="50"
|
||||
height="50"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"><metadata
|
||||
id="metadata12"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs10" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1480"
|
||||
inkscape:window-height="1046"
|
||||
id="namedview8"
|
||||
showgrid="false"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:zoom="11.8"
|
||||
inkscape:cx="24.88532"
|
||||
inkscape:cy="16.779661"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<g
|
||||
id="cog_2_"
|
||||
transform="matrix(2.25,0,0,2.25,2.5,2.5)"
|
||||
style="fill:#ffffff;fill-opacity:1">
|
||||
<g
|
||||
id="g4"
|
||||
style="fill:#ffffff;fill-opacity:1">
|
||||
<path
|
||||
d="M 19,8 H 16.69 C 16.55,7.54 16.36,7.11 16.13,6.7 L 17.83,5 c 0.39,-0.39 0.39,-1.02 0,-1.41 L 16.42,2.18 c -0.39,-0.39 -1.02,-0.39 -1.41,0 l -1.7,1.7 C 12.9,3.66 12.47,3.47 12.01,3.33 V 1 c 0,-0.55 -0.45,-1 -1,-1 H 9 C 8.45,0 8,0.45 8,1 V 3.33 C 7.52,3.47 7.06,3.67 6.63,3.91 L 5,2.28 C 4.63,1.91 4.02,1.91 3.64,2.28 L 2.28,3.64 C 1.91,4.02 1.91,4.63 2.28,5 L 3.9,6.62 C 3.66,7.06 3.46,7.51 3.31,8 H 1 C 0.45,8 0,8.45 0,9 v 2 c 0,0.55 0.45,1 1,1 h 2.31 c 0.14,0.46 0.33,0.89 0.56,1.3 L 2.17,15 c -0.39,0.39 -0.39,1.02 0,1.41 l 1.41,1.41 c 0.39,0.39 1.02,0.39 1.41,0 l 1.7,-1.7 c 0.41,0.22 0.84,0.41 1.3,0.55 V 19 c 0,0.55 0.45,1 1,1 h 2 c 0.55,0 1,-0.45 1,-1 v -2.33 c 0.48,-0.14 0.94,-0.35 1.37,-0.59 L 15,17.72 c 0.37,0.37 0.98,0.37 1.36,0 l 1.36,-1.36 c 0.37,-0.37 0.37,-0.98 0,-1.36 L 16.1,13.38 C 16.34,12.95 16.55,12.49 16.7,12 H 19 c 0.55,0 1,-0.45 1,-1 V 9 C 20,8.45 19.55,8 19,8 Z m -9,6 C 7.79,14 6,12.21 6,10 6,7.79 7.79,6 10,6 c 2.21,0 4,1.79 4,4 0,2.21 -1.79,4 -4,4 z"
|
||||
id="path2"
|
||||
inkscape:connector-curvature="0"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;fill:#ffffff;fill-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"label": "Settings",
|
||||
"tooltip": "Open settings and help"
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../../../test';
|
||||
import { stop } from '../../../hub/actions';
|
||||
import { HubRuntimeState } from '../../../hub/reducers';
|
||||
import StopButton from './StopButton';
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('should dispatch action when clicked', () => {
|
||||
const [button, dispatch] = testRender(<StopButton />, {
|
||||
hub: { runtime: HubRuntimeState.Running },
|
||||
});
|
||||
|
||||
button.getByRole('button', { name: 'Stop' }).click();
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(stop());
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
import { useI18n } from '@shopify/react-i18n';
|
||||
import React from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { stop } from '../../../hub/actions';
|
||||
import { HubRuntimeState } from '../../../hub/reducers';
|
||||
import { useSelector } from '../../../reducers';
|
||||
import ActionButton from '../../ActionButton';
|
||||
import { I18nId } from './i18n';
|
||||
import icon from './icon.svg';
|
||||
|
||||
const StopButton: React.VFC = () => {
|
||||
const runtime = useSelector((s) => s.hub.runtime);
|
||||
const keyboardShortcut = 'F6';
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [i18n] = useI18n();
|
||||
|
||||
return (
|
||||
<ActionButton
|
||||
label={i18n.translate(I18nId.Label)}
|
||||
keyboardShortcut={keyboardShortcut}
|
||||
tooltip={i18n.translate(I18nId.Tooltip, { key: keyboardShortcut })}
|
||||
icon={icon}
|
||||
enabled={runtime === HubRuntimeState.Running}
|
||||
onAction={() => dispatch(stop())}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default StopButton;
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
import { lookup } from '../../../../test';
|
||||
import { I18nId } from './i18n';
|
||||
import en from './translations/en.json';
|
||||
|
||||
describe('Ensure .json file has matches for I18nId', () => {
|
||||
test.each(Object.values(I18nId))('%s', (id) => {
|
||||
expect(lookup(en, id)).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020-2022 The Pybricks Authors
|
||||
|
||||
export enum I18nId {
|
||||
Label = 'label',
|
||||
Tooltip = 'tooltip',
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 26.458333 26.458334"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="stop.svg"
|
||||
inkscape:export-filename="button.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96">
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="light-circle-fill"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.52916667,0,0,0.52916667,-53.400128,172.5108)">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5207" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="icon-contents"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.78378378,0,0,0.78378378,-217.21909,-864.32335)">
|
||||
<stop
|
||||
style="stop-color:#3880b7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5179" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-circle-edge"
|
||||
osb:paint="solid"
|
||||
gradientTransform="matrix(0.04571075,0,0,0.26284445,-63.602396,-483.67016)">
|
||||
<stop
|
||||
style="stop-color:#b7b7b7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5173" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="dark-back"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(1195.9167,-717.54999)">
|
||||
<stop
|
||||
style="stop-color:#333333;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1439" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="dark-front"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(4643.556,-4.2349475e-6)">
|
||||
<stop
|
||||
style="stop-color:#d4d4d4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1389" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-front"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(-313.01005,-269.76128)">
|
||||
<stop
|
||||
style="stop-color:#4e4e4e;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1184" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="light-back"
|
||||
osb:paint="solid"
|
||||
gradientTransform="translate(-78.252472)">
|
||||
<stop
|
||||
style="stop-color:#eeeeee;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1172" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.313708"
|
||||
inkscape:cx="19.480688"
|
||||
inkscape:cy="15.933037"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1853"
|
||||
inkscape:window-height="1145"
|
||||
inkscape:window-x="67"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
units="px"
|
||||
inkscape:measure-start="0,0"
|
||||
inkscape:measure-end="0,0"
|
||||
inkscape:snap-global="false"
|
||||
showguides="true"
|
||||
inkscape:pagecheckerboard="true" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-270.54165)">
|
||||
<rect
|
||||
style="fill:url(#light-circle-fill);fill-opacity:1;stroke:none;stroke-width:1.58749974;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect5272"
|
||||
width="15.200954"
|
||||
height="15.200954"
|
||||
x="5.6828184"
|
||||
y="275.50818"
|
||||
inkscape:export-filename="out.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"label": "Stop",
|
||||
"tooltip": "Stop everything ({key})"
|
||||
}
|
||||