Skip to content
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
172 changes: 172 additions & 0 deletions lang/ui.en.json
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,10 @@
"defaultMessage": "Short collections of movement data lasting 1 second. Your data samples are only stored on your computer, they do not get sent to anyone else.",
"description": "Tooltip for data samples heading"
},
"default-project-name": {
"defaultMessage": "Untitled",
"description": "Default project name"
},
"delete-action-aria": {
"defaultMessage": "Delete action \"{action}\"",
"description": "Aria label for action delete icon"
Expand Down Expand Up @@ -763,6 +767,166 @@
"defaultMessage": "Language",
"description": "Language option text"
},
"led-icon-option-angry": {
"defaultMessage": "Angry",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-asleep": {
"defaultMessage": "Asleep",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-butterfly": {
"defaultMessage": "Butterfly",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-chessboard": {
"defaultMessage": "Chessboard",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-confused": {
"defaultMessage": "Confused",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-cow": {
"defaultMessage": "Cow",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-diamond": {
"defaultMessage": "Diamond",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-duck": {
"defaultMessage": "Duck",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-eighthnote": {
"defaultMessage": "Eighth Note",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-fabulous": {
"defaultMessage": "Fabulous",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-ghost": {
"defaultMessage": "Ghost",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-giraffe": {
"defaultMessage": "Giraffe",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-happy": {
"defaultMessage": "Happy",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-heart": {
"defaultMessage": "Heart",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-house": {
"defaultMessage": "House",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-lefttriangle": {
"defaultMessage": "Left Triangle",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-meh": {
"defaultMessage": "Meh",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-no": {
"defaultMessage": "No",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-pitchfork": {
"defaultMessage": "Pitchfork",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-quarternote": {
"defaultMessage": "Quarter Note",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-rabbit": {
"defaultMessage": "Rabbit",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-rollerskate": {
"defaultMessage": "Rollerskate",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-sad": {
"defaultMessage": "Sad",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-scissors": {
"defaultMessage": "Scissors",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-silly": {
"defaultMessage": "Silly",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-skull": {
"defaultMessage": "Skull",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-smalldiamond": {
"defaultMessage": "Small Diamond",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-smallheart": {
"defaultMessage": "Small Heart",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-smallsquare": {
"defaultMessage": "Small Square",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-snake": {
"defaultMessage": "Snake",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-square": {
"defaultMessage": "Square",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-stickfigure": {
"defaultMessage": "Stick Figure",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-surprised": {
"defaultMessage": "Surprised",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-sword": {
"defaultMessage": "Sword",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-target": {
"defaultMessage": "Target",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-tortoise": {
"defaultMessage": "Tortoise",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-triangle": {
"defaultMessage": "Triangle",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-tshirt": {
"defaultMessage": "T-Shirt",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-umbrella": {
"defaultMessage": "Umbrella",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"led-icon-option-yes": {
"defaultMessage": "Yes",
"description": "Makecode icon option. The translation should match MakeCode translations."
},
"live-data-graph": {
"defaultMessage": "Live data graph",
"description": "Title for live data graph"
Expand Down Expand Up @@ -1079,6 +1243,14 @@
"defaultMessage": "Your hex file has been downloaded",
"description": "Notification after a hex file has been downloaded"
},
"select-icon-action-aria": {
"defaultMessage": "Pick icon",
"description": "Aria label for pick icon button"
},
"select-icon-option-action-aria": {
"defaultMessage": "Select \"{iconName}\" icon",
"description": "Aria label for icon option"
},
"settings-menu-action": {
"defaultMessage": "Settings actions menu",
"description": "Label for settings actions menu button"
Expand Down
5 changes: 4 additions & 1 deletion src/components/CodeViewDefaultBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ const CodeViewDefaultBlock = ({
}: CodeViewDefaultBlockProps) => {
const intl = useIntl();
const ledPattern = makecodeIcons[icon];
const iconName = intl.formatMessage({
id: `led-icon-option-${icon.toLowerCase()}`,
});
const actionNameTextBoxWidth = getActionNameTextBoxWidth(actionName);
const dropdownArrowXPos = actionNameTextBoxWidth - 20;
const onMlStartBlockWidth = actionNameTextBoxWidth + 120;
Expand All @@ -21,7 +24,7 @@ const CodeViewDefaultBlock = ({
role="image"
aria-label={intl.formatMessage(
{ id: "makecode-block-default-alt" },
{ actionName: actionName, iconName: icon }
{ actionName, iconName }
)}
>
<svg
Expand Down
4 changes: 2 additions & 2 deletions src/components/DataSamplesMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { ConfirmDialog } from "./ConfirmDialog";
import LoadProjectMenuItem from "./LoadProjectMenuItem";
import { NameProjectDialog } from "./NameProjectDialog";
import ViewDataFeaturesMenuItem from "./ViewDataFeaturesMenuItem";
import { useProjectIsUntitled } from "../hooks/project-hooks";

const DataSamplesMenu = () => {
const intl = useIntl();
Expand All @@ -38,8 +39,7 @@ const DataSamplesMenu = () => {
const { stage } = useConnectionStage();
const deleteConfirmDisclosure = useDisclosure();
const nameProjectDialogDisclosure = useDisclosure();
const projectName = useStore((s) => s.project.header?.name);
const isUntitled = projectName === "Untitled";
const isUntitled = useProjectIsUntitled();
const setProjectName = useStore((s) => s.setProjectName);

const download = useCallback(() => {
Expand Down
13 changes: 11 additions & 2 deletions src/components/LedIconPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import { memo, useCallback } from "react";
import { RiArrowDropDownFill } from "react-icons/ri";
import { MakeCodeIcon, makecodeIcons } from "../utils/icons";
import LedIcon from "./LedIcon";
import { useIntl } from "react-intl";

interface LedIconPicker {
onIconSelected: (icon: MakeCodeIcon) => void;
}

const LedIconPicker = ({ onIconSelected }: LedIconPicker) => {
const intl = useIntl();
const handleClick = useCallback(
(icon: MakeCodeIcon, callback: () => void) => {
onIconSelected(icon);
Expand All @@ -33,7 +35,7 @@ const LedIconPicker = ({ onIconSelected }: LedIconPicker) => {
<IconButton
variant="ghost"
color="blackAlpha.700"
aria-label="Pick icon"
aria-label={intl.formatMessage({ id: "select-icon-action-aria" })}
size="sm"
>
<RiArrowDropDownFill size={32} />
Expand All @@ -46,7 +48,14 @@ const LedIconPicker = ({ onIconSelected }: LedIconPicker) => {
{Object.keys(makecodeIcons).map((icon, idx) => (
<IconButton
key={idx}
aria-label={`Select ${icon} icon`}
aria-label={intl.formatMessage(
{ id: "select-icon-option-action-aria" },
{
iconName: intl.formatMessage({
id: `led-icon-option-${icon.toLowerCase()}`,
}),
}
)}
onClick={() => handleClick(icon as MakeCodeIcon, onClose)}
variant="unstyled"
h={20}
Expand Down
4 changes: 2 additions & 2 deletions src/components/NameProjectDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import {
} from "@chakra-ui/react";
import { useCallback, useState } from "react";
import { FormattedMessage } from "react-intl";
import { useProjectName } from "../hooks/project-hooks";
import { validateProjectName } from "../project-name";
import { useStore } from "../store";

interface NameProjectDialogProps {
onClose: () => void;
Expand All @@ -37,7 +37,7 @@ export const NameProjectDialog = ({
isOpen,
onSave,
}: NameProjectDialogProps) => {
const initialName = useStore((s) => s.project.header?.name ?? "");
const initialName = useProjectName();
const [name, setName] = useState<string>(initialName);
const isValid = validateProjectName(name);
const ref = useCallback((input: HTMLInputElement | null) => {
Expand Down
6 changes: 2 additions & 4 deletions src/components/SaveDialogs.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import { useCallback } from "react";
import { useProject } from "../hooks/project-hooks";
import { useProjectIsUntitled, useProject } from "../hooks/project-hooks";
import { useStore } from "../store";
import SaveHelpDialog from "./SaveHelpDialog";
import SaveProgressDialog from "./SaveProgressDialog";
import { SaveStep } from "../model";
import { NameProjectDialog } from "./NameProjectDialog";
import { defaultProjectName } from "../project-name";

const SaveDialogs = () => {
const setSave = useStore((s) => s.setSave);
const projectName = useStore((s) => s.project.header?.name);
const isUntitled = projectName === defaultProjectName;
const isUntitled = useProjectIsUntitled();
const { step, hex } = useStore((s) => s.save);
const setProjectName = useStore((s) => s.setProjectName);
const { saveHex } = useProject();
Expand Down
41 changes: 32 additions & 9 deletions src/hooks/project-hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,19 @@ import {
PostImportDialogState,
SaveStep,
} from "../model";
import { defaultProjectName } from "../project-name";
import { untitledProjectName as untitled } from "../project-name";
import { useStore } from "../store";
import {
createCodePageUrl,
createDataSamplesPageUrl,
createTestingModelPageUrl,
} from "../urls";
import { getTotalNumSamples } from "../utils/actions";
import {
downloadHex,
getLowercaseFileExtension,
readFileAsText,
} from "../utils/fs-util";
import { getTotalNumSamples } from "../utils/actions";
import { useDownloadActions } from "./download-hooks";

class CodeEditorError extends Error {}
Expand Down Expand Up @@ -85,6 +85,26 @@ interface ProjectProviderProps {
children: ReactNode;
}

const useDefaultProjectName = (): string => {
const intl = useIntl();
return intl.formatMessage({ id: "default-project-name" });
};

export const useProjectIsUntitled = (): boolean => {
const translatedUntitled = useDefaultProjectName();
const projectName = useStore((s) => s.project.header?.name);
return projectName === untitled || projectName === translatedUntitled;
};

export const useProjectName = (): string => {
const isUntitled = useProjectIsUntitled();
const translatedUntitled = useDefaultProjectName();
const projectName = useStore((s) =>
!s.project.header || isUntitled ? translatedUntitled : s.project.header.name
);
return projectName;
};

export const ProjectProvider = ({
driverRef,
children,
Expand Down Expand Up @@ -210,13 +230,15 @@ export const ProjectProvider = ({
const settings = useStore((s) => s.settings);
const actions = useStore((s) => s.actions);
const saveNextDownloadRef = useRef(false);
const translatedUntitled = useDefaultProjectName();
const saveHex = useCallback(
async (hex?: HexData): Promise<void> => {
const { step } = save;
const projectName = getCurrentProject().header?.name;
if (settings.showPreSaveHelp && step === SaveStep.None) {
setSave({ hex, step: SaveStep.PreSaveHelp });
} else if (
getCurrentProject().header?.name === defaultProjectName &&
(projectName === untitled || projectName === translatedUntitled) &&
step === SaveStep.None
) {
setSave({ hex, step: SaveStep.ProjectName });
Expand Down Expand Up @@ -249,16 +271,17 @@ export const ProjectProvider = ({
}
},
[
save,
getCurrentProject,
settings.showPreSaveHelp,
translatedUntitled,
setSave,
doAfterEditorUpdate,
driverRef,
actions,
getCurrentProject,
intl,
logging,
save,
setSave,
settings.showPreSaveHelp,
actions,
toast,
intl,
]
);

Expand Down
Loading
Loading