diff --git a/CHANGELOG.md b/CHANGELOG.md
index c8872fbaa..917350389 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -76,6 +76,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Improvements
+- [#553](https://github.com/alleslabs/celatone-frontend/pull/553) Use Cmd on Mac OS while Ctrl on others
- [#548](https://github.com/alleslabs/celatone-frontend/pull/548) Handle interaction page query param and refactor page
- [#546](https://github.com/alleslabs/celatone-frontend/pull/546) Handle 404 on the current selected chain
- [#540](https://github.com/alleslabs/celatone-frontend/pull/540) Add open proposal configuration
diff --git a/src/lib/app-provider/hooks/index.ts b/src/lib/app-provider/hooks/index.ts
index 1c16c0e72..adec0f195 100644
--- a/src/lib/app-provider/hooks/index.ts
+++ b/src/lib/app-provider/hooks/index.ts
@@ -14,3 +14,4 @@ export * from "./useConfig";
export * from "./useCurrentChain";
export * from "./useConvertHexAddress";
export * from "./usePreviousPathname";
+export * from "./usePlatform";
diff --git a/src/lib/app-provider/hooks/usePlatform.ts b/src/lib/app-provider/hooks/usePlatform.ts
new file mode 100644
index 000000000..c03f690f2
--- /dev/null
+++ b/src/lib/app-provider/hooks/usePlatform.ts
@@ -0,0 +1,16 @@
+import { useMemo } from "react";
+
+export const usePlatform = () => {
+ return useMemo(() => {
+ if (typeof navigator === "undefined") {
+ return "Unknown";
+ }
+ const { userAgent } = navigator;
+ const isMac = /Mac OS X/.test(userAgent);
+ return isMac ? "Mac" : "Windows";
+ }, []);
+};
+
+export const useIsMac = () => {
+ return usePlatform() === "Mac";
+};
diff --git a/src/lib/pages/execute/components/JsonExecute.tsx b/src/lib/pages/execute/components/JsonExecute.tsx
index febcb971a..cdae57f55 100644
--- a/src/lib/pages/execute/components/JsonExecute.tsx
+++ b/src/lib/pages/execute/components/JsonExecute.tsx
@@ -10,6 +10,7 @@ import {
useExecuteContractTx,
useCurrentChain,
useMobile,
+ useIsMac,
} from "lib/app-provider";
import { useAttachFunds } from "lib/app-provider/hooks/useAttachFunds";
import { useSimulateFeeQuery } from "lib/app-provider/queries";
@@ -63,6 +64,7 @@ export const JsonExecute = ({
// --------------DEPENDENCIES----------------//
// ------------------------------------------//
const isMobile = useMobile();
+ const isMac = useIsMac();
const { address } = useCurrentChain();
const fabricateFee = useFabricateFee();
const executeTx = useExecuteContractTx();
@@ -237,10 +239,12 @@ export const JsonExecute = ({
assetsSelect,
]);
+ const isButtonDisabled = !enableExecute || !fee || isFetching;
useEffect(() => {
const keydownHandler = (e: KeyboardEvent) => {
// TODO: problem with safari if focusing in the textarea
- if (e.ctrlKey && e.key === "Enter") {
+ const specialKey = isMac ? e.metaKey : e.ctrlKey;
+ if (!isButtonDisabled && specialKey && e.key === "Enter") {
proceed();
}
};
@@ -294,12 +298,12 @@ export const JsonExecute = ({
fontSize="14px"
p="6px 16px"
onClick={proceed}
- isDisabled={!enableExecute || !fee || isFetching}
+ isDisabled={isButtonDisabled}
leftIcon={}
isLoading={processing}
sx={{ pointerEvents: processing && "none" }}
>
- Execute {!isMobile && "(Ctrl + Enter)"}
+ Execute {!isMobile && ` (${isMac ? "⌘" : "Ctrl"} + Enter)`}
diff --git a/src/lib/pages/interact/component/form/ExecuteArea.tsx b/src/lib/pages/interact/component/form/ExecuteArea.tsx
index f2e8dea8b..56578142f 100644
--- a/src/lib/pages/interact/component/form/ExecuteArea.tsx
+++ b/src/lib/pages/interact/component/form/ExecuteArea.tsx
@@ -9,6 +9,7 @@ import {
useSimulateFeeQuery,
useExecuteModuleTx,
useCurrentChain,
+ useIsMac,
} from "lib/app-provider";
import { AbiForm } from "lib/components/abi";
import { ConnectWalletAlert } from "lib/components/ConnectWalletAlert";
@@ -35,6 +36,7 @@ export const ExecuteArea = ({
? fn.params.slice(1)
: fn.params;
+ const isMac = useIsMac();
const { address } = useCurrentChain();
const fabricateFee = useFabricateFee();
const executeModuleTx = useExecuteModuleTx();
@@ -119,6 +121,21 @@ export const ExecuteArea = ({
return () => {};
}, [address, data, enableExecute, executeFn, moduleAddress, moduleName]);
+ const isButtonDisabled = !enableExecute || !fee || isFetching;
+ useEffect(() => {
+ const keydownHandler = (e: KeyboardEvent) => {
+ // TODO: problem with safari if focusing in the textarea
+ const specialKey = isMac ? e.metaKey : e.ctrlKey;
+ if (!isButtonDisabled && specialKey && e.key === "Enter") {
+ proceed();
+ }
+ };
+ document.addEventListener("keydown", keydownHandler);
+ return () => {
+ document.removeEventListener("keydown", keydownHandler);
+ };
+ });
+
return (
{fn.is_entry ? (
@@ -166,12 +183,12 @@ export const ExecuteArea = ({
fontSize="14px"
p="6px 16px"
onClick={proceed}
- isDisabled={!enableExecute || !fee || isFetching}
+ isDisabled={isButtonDisabled}
leftIcon={}
isLoading={processing}
sx={{ pointerEvents: processing && "none" }}
>
- Execute
+ Execute{` (${isMac ? "⌘" : "Ctrl"} + Enter)`}
diff --git a/src/lib/pages/interact/component/form/ViewArea.tsx b/src/lib/pages/interact/component/form/ViewArea.tsx
index 579100ba8..7f3cbf693 100644
--- a/src/lib/pages/interact/component/form/ViewArea.tsx
+++ b/src/lib/pages/interact/component/form/ViewArea.tsx
@@ -9,8 +9,9 @@ import {
Spinner,
Text,
} from "@chakra-ui/react";
-import { useState } from "react";
+import { useEffect, useState } from "react";
+import { useIsMac } from "lib/app-provider";
import { AbiForm } from "lib/components/abi";
import { CustomIcon } from "lib/components/icon";
import JsonReadOnly from "lib/components/json/JsonReadOnly";
@@ -34,6 +35,7 @@ export const ViewArea = ({
moduleName: string;
fn: ExposedFunction;
}) => {
+ const isMac = useIsMac();
const [abiData, setAbiData] = useState({
typeArgs: getAbiInitialData(fn.generic_type_params.length),
args: getAbiInitialData(fn.params.length),
@@ -61,7 +63,19 @@ export const ViewArea = ({
};
const isLoading = queryFetching || queryRefetching;
- const isDisabled = Boolean(abiErrors.length);
+ const isButtonDisabled = Boolean(abiErrors.length);
+ useEffect(() => {
+ const keydownHandler = (e: KeyboardEvent) => {
+ // TODO: problem with safari if focusing in the textarea
+ const specialKey = isMac ? e.metaKey : e.ctrlKey;
+ if (!isButtonDisabled && specialKey && e.key === "Enter") handleQuery();
+ };
+ document.addEventListener("keydown", keydownHandler);
+ return () => {
+ document.removeEventListener("keydown", keydownHandler);
+ };
+ });
+
return (
@@ -79,11 +93,11 @@ export const ViewArea = ({
p="6px 16px"
size={{ base: "sm", md: "md" }}
onClick={handleQuery}
- isDisabled={isDisabled}
+ isDisabled={isButtonDisabled}
isLoading={isLoading}
leftIcon={}
>
- View
+ View{` (${isMac ? "⌘" : "Ctrl"} + Enter)`}
diff --git a/src/lib/pages/query/components/JsonQuery.tsx b/src/lib/pages/query/components/JsonQuery.tsx
index b6857989a..399a0430d 100644
--- a/src/lib/pages/query/components/JsonQuery.tsx
+++ b/src/lib/pages/query/components/JsonQuery.tsx
@@ -9,6 +9,7 @@ import {
CELATONE_QUERY_KEYS,
useBaseApiRoute,
useCurrentChain,
+ useIsMac,
useMobile,
} from "lib/app-provider";
import { ContractCmdButton } from "lib/components/ContractCmdButton";
@@ -42,6 +43,7 @@ interface JsonQueryProps {
export const JsonQuery = ({ contractAddress, initialMsg }: JsonQueryProps) => {
const { track, trackAction } = useTrack();
const isMobile = useMobile();
+ const isMac = useIsMac();
const { isFetching: cmdsFetching, queryCmds } = useQueryCmds(contractAddress);
const lcdEndpoint = useBaseApiRoute("rest");
const { addActivity } = useContractStore();
@@ -88,10 +90,12 @@ export const JsonQuery = ({ contractAddress, initialMsg }: JsonQueryProps) => {
refetch();
};
+ const isButtonDisabled = jsonValidate(msg) !== null;
useEffect(() => {
const keydownHandler = (e: KeyboardEvent) => {
// TODO: problem with safari if focusing in the textarea
- if (e.ctrlKey && e.key === "Enter") handleQuery();
+ const specialKey = isMac ? e.metaKey : e.ctrlKey;
+ if (!isButtonDisabled && specialKey && e.key === "Enter") handleQuery();
};
document.addEventListener("keydown", keydownHandler);
return () => {
@@ -161,11 +165,11 @@ export const JsonQuery = ({ contractAddress, initialMsg }: JsonQueryProps) => {
p="6px 16px"
size={{ base: "sm", md: "md" }}
onClick={handleQuery}
- isDisabled={jsonValidate(msg) !== null}
+ isDisabled={isButtonDisabled}
isLoading={queryFetching || queryRefetching}
leftIcon={}
>
- Query {!isMobile && "(Ctrl + Enter)"}
+ Query{!isMobile && ` (${isMac ? "⌘" : "Ctrl"} + Enter)`}