mirror of https://github.com/jetkvm/kvm.git
Settings macros pages
This commit is contained in:
parent
214bd69d10
commit
1647b80b8c
|
|
@ -185,7 +185,7 @@
|
|||
"connection_stats_video_description": "The video stream from the JetKVM to the client.",
|
||||
"connection_stats_video": "Video",
|
||||
"continue": "Continue",
|
||||
"creating_peer_connection": "Creating peer connection...",
|
||||
"creating_peer_connection": "Creating peer connection…",
|
||||
"dc_power_control_current_unit": "A",
|
||||
"dc_power_control_current": "Current",
|
||||
"dc_power_control_get_state_error": "Failed to get DC power state: {error}",
|
||||
|
|
@ -236,7 +236,7 @@
|
|||
"extensions_dc_power_control_description": "Control your DC Power extension",
|
||||
"extensions_dc_power_control": "DC Power Control",
|
||||
"extensions_popover_extensions": "Extensions",
|
||||
"gathering_ice_candidates": "Gathering ICE candidates...",
|
||||
"gathering_ice_candidates": "Gathering ICE candidates…",
|
||||
"general_app_version": "App: {version}",
|
||||
"general_auto_update_description": "Automatically update the device to the latest version",
|
||||
"general_auto_update_error": "Failed to set auto-update: {error}",
|
||||
|
|
@ -258,7 +258,7 @@
|
|||
"general_update_background_button": "Update in Background",
|
||||
"general_update_check_again_button": "Check Again",
|
||||
"general_update_checking_description": "We're ensuring your device has the latest features and improvements.",
|
||||
"general_update_checking_title": "Checking for updates...",
|
||||
"general_update_checking_title": "Checking for updates…",
|
||||
"general_update_completed_description": "Your device has been successfully updated to the latest version. Enjoy the new features and improvements!",
|
||||
"general_update_completed_title": "Update Completed Successfully",
|
||||
"general_update_error_description": "An error occurred while updating your device. Please try again later.",
|
||||
|
|
@ -266,12 +266,12 @@
|
|||
"general_update_error_title": "Update Error",
|
||||
"general_update_later_button": "Do it later",
|
||||
"general_update_now_button": "Update Now",
|
||||
"general_update_rebooting": "Rebooting to complete the update...",
|
||||
"general_update_rebooting": "Rebooting to complete the update…",
|
||||
"general_update_status_awaiting_reboot": "Awaiting reboot",
|
||||
"general_update_status_downloading": "Downloading {update_type} update...",
|
||||
"general_update_status_fetching": "Fetching update information...",
|
||||
"general_update_status_installing": "Installing {update_type} update...",
|
||||
"general_update_status_verifying": "Verifying {update_type} update...",
|
||||
"general_update_status_downloading": "Downloading {update_type} update…",
|
||||
"general_update_status_fetching": "Fetching update information…",
|
||||
"general_update_status_installing": "Installing {update_type} update…",
|
||||
"general_update_status_verifying": "Verifying {update_type} update…",
|
||||
"general_update_system_type": "System",
|
||||
"general_update_system_update_title": "Linux System Update",
|
||||
"general_update_up_to_date_description": "Your system is running the latest version. No updates are currently available.",
|
||||
|
|
@ -438,6 +438,54 @@
|
|||
"macro_step_search_for_key": "Search for key…",
|
||||
"macro_steps_description": "Keys/modifiers executed in sequence with a delay between each step.",
|
||||
"macro_steps_label": "Steps",
|
||||
"macros_add_description": "Create a new keyboard macro",
|
||||
"macros_add_new": "Add New Macro",
|
||||
"macros_create_first": "Create your first macro to get started",
|
||||
"macros_created_success": "Macro \"{name}\" created successfully",
|
||||
"macros_delete_confirm": "Are you sure you want to delete this macro? This action cannot be undone.",
|
||||
"macros_delete_macro": "Delete Macro",
|
||||
"macros_deleted_success": "Macro \"{name}\" deleted successfully",
|
||||
"macros_deleting": "Deleting",
|
||||
"macros_duplicate": "Duplicate",
|
||||
"macros_duplicated_success": "Macro \"{name}\" duplicated successfully",
|
||||
"macros_edit_description": "Modify your keyboard macro",
|
||||
"macros_edit_title": "Edit Macro",
|
||||
"macros_edit": "Edit",
|
||||
"macros_failed_create": "Failed to create macro",
|
||||
"macros_failed_create_error": "Failed to create macro: {error}",
|
||||
"macros_failed_delete": "Failed to delete macro",
|
||||
"macros_failed_delete_error": "Failed to delete macro: {error}",
|
||||
"macros_failed_duplicate": "Failed to duplicate macro",
|
||||
"macros_failed_duplicate_error": "Failed to duplicate macro: {error}",
|
||||
"macros_failed_reorder": "Failed to reorder macros",
|
||||
"macros_failed_reorder_error": "Failed to reorder macros: {error}",
|
||||
"macros_failed_update": "Failed to update macro",
|
||||
"macros_failed_update_error": "Failed to update macro: {error}",
|
||||
"macros_invalid_data": "Invalid macro data",
|
||||
"macros_maximum_macros_reached": "You have reached the maximum number of {maximum} macros allowed.",
|
||||
"macros_move_down": "Move Down",
|
||||
"macros_move_up": "Move Up",
|
||||
"macros_no_macros_available": "No macros available",
|
||||
"macros_no_macros_found": "No macros found",
|
||||
"macros_order_updated": "Macro order updated successfully",
|
||||
"macros_title": "Keyboard Macros",
|
||||
"macros_updated_success": "Macro \"{name}\" updated successfully",
|
||||
"macros_aria_delete": "Delete macro {name}",
|
||||
"macros_aria_duplicate": "Duplicate macro {name}",
|
||||
"macros_aria_edit": "Edit macro {name}",
|
||||
"macros_aria_move_down": "Move {name} down",
|
||||
"macros_aria_move_up": "Move {name} up",
|
||||
"macros_confirm_delete_description": "Are you sure you want to delete \"{name}\"? This action cannot be undone.",
|
||||
"macros_confirm_delete_title": "Delete Macro",
|
||||
"macros_confirm_deleting": "Deleting…",
|
||||
"macros_add_new_macro": "Add New Macro",
|
||||
"macros_aria_add_new": "Add new macro",
|
||||
"macros_create_first_headline": "Create Your First Macro",
|
||||
"macros_create_first_description": "Combine keystrokes into a single action",
|
||||
"macros_delay_only": "Delay only",
|
||||
"macros_edit_button": "Edit",
|
||||
"macros_loading": "Loading macros…",
|
||||
"macros_max_reached": "Max Reached",
|
||||
"metric_not_supported": "Metric not supported",
|
||||
"metric_waiting_for_data": "Waiting for data…",
|
||||
"mount_add_file_to_get_started": "Add a file to get started",
|
||||
|
|
|
|||
|
|
@ -1,24 +1,19 @@
|
|||
import { useNavigate } from "react-router";
|
||||
import { useState } from "react";
|
||||
import { useNavigate } from "react-router";
|
||||
|
||||
import { KeySequence, useMacrosStore, generateMacroId } from "@/hooks/stores";
|
||||
import { SettingsPageHeader } from "@/components/SettingsPageheader";
|
||||
import { MacroForm } from "@/components/MacroForm";
|
||||
import { KeySequence, useMacrosStore, generateMacroId } from "@hooks/stores";
|
||||
import { MacroForm } from "@components/MacroForm";
|
||||
import { SettingsPageHeader } from "@components/SettingsPageheader";
|
||||
import { DEFAULT_DELAY } from "@/constants/macros";
|
||||
import notifications from "@/notifications";
|
||||
import { normalizeSortOrders } from "@/utils";
|
||||
import { m } from "@localizations/messages.js";
|
||||
|
||||
export default function SettingsMacrosAddRoute() {
|
||||
const { macros, saveMacros } = useMacrosStore();
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const normalizeSortOrders = (macros: KeySequence[]): KeySequence[] => {
|
||||
return macros.map((macro, index) => ({
|
||||
...macro,
|
||||
sortOrder: index + 1,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleAddMacro = async (macro: Partial<KeySequence>) => {
|
||||
setIsSaving(true);
|
||||
try {
|
||||
|
|
@ -30,13 +25,13 @@ export default function SettingsMacrosAddRoute() {
|
|||
};
|
||||
|
||||
await saveMacros(normalizeSortOrders([...macros, newMacro]));
|
||||
notifications.success(`Macro "${newMacro.name}" created successfully`);
|
||||
notifications.success(m.macros_created_success({name: newMacro.name}));
|
||||
navigate("../");
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
notifications.error(`Failed to create macro: ${error.message}`);
|
||||
notifications.error(m.macros_failed_create_error({error: error.message || m.unknown_error() }));
|
||||
} else {
|
||||
notifications.error("Failed to create macro");
|
||||
notifications.error(m.macros_failed_create());
|
||||
}
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
|
|
@ -46,8 +41,8 @@ export default function SettingsMacrosAddRoute() {
|
|||
return (
|
||||
<div className="space-y-4">
|
||||
<SettingsPageHeader
|
||||
title="Add New Macro"
|
||||
description="Create a new keyboard macro"
|
||||
title={m.macros_add_new()}
|
||||
description={m.macros_add_description()}
|
||||
/>
|
||||
<MacroForm
|
||||
initialData={{
|
||||
|
|
|
|||
|
|
@ -1,20 +1,15 @@
|
|||
import { useNavigate, useParams } from "react-router";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useNavigate, useParams } from "react-router";
|
||||
import { LuTrash2 } from "react-icons/lu";
|
||||
|
||||
import { KeySequence, useMacrosStore } from "@/hooks/stores";
|
||||
import { SettingsPageHeader } from "@/components/SettingsPageheader";
|
||||
import { MacroForm } from "@/components/MacroForm";
|
||||
import { KeySequence, useMacrosStore } from "@hooks/stores";
|
||||
import { Button } from "@components/Button";
|
||||
import { ConfirmDialog } from "@components/ConfirmDialog";
|
||||
import { MacroForm } from "@components/MacroForm";
|
||||
import { SettingsPageHeader } from "@components/SettingsPageheader";
|
||||
import notifications from "@/notifications";
|
||||
import { Button } from "@/components/Button";
|
||||
import { ConfirmDialog } from "@/components/ConfirmDialog";
|
||||
|
||||
const normalizeSortOrders = (macros: KeySequence[]): KeySequence[] => {
|
||||
return macros.map((macro, index) => ({
|
||||
...macro,
|
||||
sortOrder: index + 1,
|
||||
}));
|
||||
};
|
||||
import { normalizeSortOrders } from "@/utils";
|
||||
import { m } from "@localizations/messages.js";
|
||||
|
||||
export default function SettingsMacrosEditRoute() {
|
||||
const { macros, saveMacros } = useMacrosStore();
|
||||
|
|
@ -56,13 +51,13 @@ export default function SettingsMacrosEditRoute() {
|
|||
);
|
||||
|
||||
await saveMacros(normalizeSortOrders(newMacros));
|
||||
notifications.success(`Macro "${updatedMacro.name}" updated successfully`);
|
||||
notifications.success(m.macros_updated_success({ name: updatedMacro.name }));
|
||||
navigate("../");
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
notifications.error(`Failed to update macro: ${error.message}`);
|
||||
notifications.error(m.macros_failed_update({ error: error.message }));
|
||||
} else {
|
||||
notifications.error("Failed to update macro");
|
||||
notifications.error(m.macros_failed_update());
|
||||
}
|
||||
} finally {
|
||||
setIsUpdating(false);
|
||||
|
|
@ -76,13 +71,13 @@ export default function SettingsMacrosEditRoute() {
|
|||
try {
|
||||
const updatedMacros = normalizeSortOrders(macros.filter(m => m.id !== macro.id));
|
||||
await saveMacros(updatedMacros);
|
||||
notifications.success(`Macro "${macro.name}" deleted successfully`);
|
||||
notifications.success(m.macros_deleted_success({ name: macro.name }));
|
||||
navigate("../macros");
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
notifications.error(`Failed to delete macro: ${error.message}`);
|
||||
notifications.error(m.macros_failed_delete_error({ error: error.message }));
|
||||
} else {
|
||||
notifications.error("Failed to delete macro");
|
||||
notifications.error(m.macros_failed_delete());
|
||||
}
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
|
|
@ -95,13 +90,13 @@ export default function SettingsMacrosEditRoute() {
|
|||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<SettingsPageHeader
|
||||
title="Edit Macro"
|
||||
description="Modify your keyboard macro"
|
||||
title={m.macros_edit_title()}
|
||||
description={m.macros_edit_description()}
|
||||
/>
|
||||
<Button
|
||||
size="SM"
|
||||
theme="light"
|
||||
text="Delete Macro"
|
||||
|
||||
className="text-red-500 dark:text-red-400"
|
||||
LeadingIcon={LuTrash2}
|
||||
onClick={() => setShowDeleteConfirm(true)}
|
||||
|
|
@ -118,10 +113,10 @@ export default function SettingsMacrosEditRoute() {
|
|||
<ConfirmDialog
|
||||
open={showDeleteConfirm}
|
||||
onClose={() => setShowDeleteConfirm(false)}
|
||||
title="Delete Macro"
|
||||
description="Are you sure you want to delete this macro? This action cannot be undone."
|
||||
title={m.macros_delete_macro()}
|
||||
description={m.macros_delete_confirm()}
|
||||
variant="danger"
|
||||
confirmText={isDeleting ? "Deleting" : "Delete"}
|
||||
confirmText={isDeleting ? m.macros_deleting() : m.delete()}
|
||||
onConfirm={() => {
|
||||
handleDeleteMacro();
|
||||
setShowDeleteConfirm(false);
|
||||
|
|
|
|||
|
|
@ -11,23 +11,18 @@ import {
|
|||
LuCommand,
|
||||
} from "react-icons/lu";
|
||||
|
||||
import { KeySequence, useMacrosStore, generateMacroId } from "@/hooks/stores";
|
||||
import { SettingsPageHeader } from "@/components/SettingsPageheader";
|
||||
import { Button } from "@/components/Button";
|
||||
import EmptyCard from "@/components/EmptyCard";
|
||||
import Card from "@/components/Card";
|
||||
import { MAX_TOTAL_MACROS, COPY_SUFFIX, DEFAULT_DELAY } from "@/constants/macros";
|
||||
import { KeySequence, useMacrosStore, generateMacroId } from "@hooks/stores";
|
||||
import useKeyboardLayout from "@hooks/useKeyboardLayout";
|
||||
import { SettingsPageHeader } from "@components/SettingsPageheader";
|
||||
import { Button } from "@components/Button";
|
||||
import Card from "@components/Card";
|
||||
import { ConfirmDialog } from "@components/ConfirmDialog";
|
||||
import EmptyCard from "@components/EmptyCard";
|
||||
import LoadingSpinner from "@components/LoadingSpinner";
|
||||
import notifications from "@/notifications";
|
||||
import { ConfirmDialog } from "@/components/ConfirmDialog";
|
||||
import LoadingSpinner from "@/components/LoadingSpinner";
|
||||
import useKeyboardLayout from "@/hooks/useKeyboardLayout";
|
||||
|
||||
const normalizeSortOrders = (macros: KeySequence[]): KeySequence[] => {
|
||||
return macros.map((macro, index) => ({
|
||||
...macro,
|
||||
sortOrder: index + 1,
|
||||
}));
|
||||
};
|
||||
import { normalizeSortOrders } from "@/utils";
|
||||
import { MAX_TOTAL_MACROS, COPY_SUFFIX, DEFAULT_DELAY } from "@/constants/macros";
|
||||
import { m } from "@localizations/messages.js";
|
||||
|
||||
export default function SettingsMacrosRoute() {
|
||||
const { macros, loading, initialized, loadMacros, saveMacros } = useMacrosStore();
|
||||
|
|
@ -51,12 +46,12 @@ export default function SettingsMacrosRoute() {
|
|||
const handleDuplicateMacro = useCallback(
|
||||
async (macro: KeySequence) => {
|
||||
if (!macro?.id || !macro?.name) {
|
||||
notifications.error("Invalid macro data");
|
||||
notifications.error(m.macros_invalid_data());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMaxMacrosReached) {
|
||||
notifications.error(`Maximum of ${MAX_TOTAL_MACROS} macros allowed`);
|
||||
notifications.error(m.macros_maximum_macros_reached({ maximum: MAX_TOTAL_MACROS }));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -71,12 +66,12 @@ export default function SettingsMacrosRoute() {
|
|||
|
||||
try {
|
||||
await saveMacros(normalizeSortOrders([...macros, newMacroCopy]));
|
||||
notifications.success(`Macro "${newMacroCopy.name}" duplicated successfully`);
|
||||
notifications.success(m.macros_duplicated_success({ name: newMacroCopy.name }));
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
notifications.error(`Failed to duplicate macro: ${error.message}`);
|
||||
notifications.error(m.macros_failed_duplicate_error({ error: error.message || m.unknown_error() }));
|
||||
} else {
|
||||
notifications.error("Failed to duplicate macro");
|
||||
notifications.error(m.macros_failed_duplicate());
|
||||
}
|
||||
} finally {
|
||||
setActionLoadingId(null);
|
||||
|
|
@ -88,7 +83,7 @@ export default function SettingsMacrosRoute() {
|
|||
const handleMoveMacro = useCallback(
|
||||
async (index: number, direction: "up" | "down", macroId: string) => {
|
||||
if (!Array.isArray(macros) || macros.length === 0) {
|
||||
notifications.error("No macros available");
|
||||
notifications.error(m.macros_no_macros_available());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -103,12 +98,12 @@ export default function SettingsMacrosRoute() {
|
|||
const updatedMacros = normalizeSortOrders(newMacros);
|
||||
|
||||
await saveMacros(updatedMacros);
|
||||
notifications.success("Macro order updated successfully");
|
||||
notifications.success(m.macros_order_updated());
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
notifications.error(`Failed to reorder macros: ${error.message}`);
|
||||
notifications.error(m.macros_failed_reorder_error({ error: error.message || m.unknown_error() }));
|
||||
} else {
|
||||
notifications.error("Failed to reorder macros");
|
||||
notifications.error(m.macros_failed_reorder());
|
||||
}
|
||||
} finally {
|
||||
setActionLoadingId(null);
|
||||
|
|
@ -126,14 +121,14 @@ export default function SettingsMacrosRoute() {
|
|||
macros.filter(m => m.id !== macroToDelete.id),
|
||||
);
|
||||
await saveMacros(updatedMacros);
|
||||
notifications.success(`Macro "${macroToDelete.name}" deleted successfully`);
|
||||
notifications.success(m.macros_deleted_success({ name: macroToDelete.name }));
|
||||
setShowDeleteConfirm(false);
|
||||
setMacroToDelete(null);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
notifications.error(`Failed to delete macro: ${error.message}`);
|
||||
notifications.error(m.macros_failed_delete_error({ error: error.message || m.unknown_error() }));
|
||||
} else {
|
||||
notifications.error("Failed to delete macro");
|
||||
notifications.error(m.macros_failed_delete());
|
||||
}
|
||||
} finally {
|
||||
setActionLoadingId(null);
|
||||
|
|
@ -153,7 +148,7 @@ export default function SettingsMacrosRoute() {
|
|||
onClick={() => handleMoveMacro(index, "up", macro.id)}
|
||||
disabled={index === 0 || actionLoadingId === macro.id}
|
||||
LeadingIcon={LuArrowUp}
|
||||
aria-label={`Move ${macro.name} up`}
|
||||
aria-label={m.macros_aria_move_up({ name: macro.name })}
|
||||
/>
|
||||
<Button
|
||||
size="XS"
|
||||
|
|
@ -161,7 +156,7 @@ export default function SettingsMacrosRoute() {
|
|||
onClick={() => handleMoveMacro(index, "down", macro.id)}
|
||||
disabled={index === macros.length - 1 || actionLoadingId === macro.id}
|
||||
LeadingIcon={LuArrowDown}
|
||||
aria-label={`Move ${macro.name} down`}
|
||||
aria-label={m.macros_aria_move_down({ name: macro.name })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
@ -189,10 +184,7 @@ export default function SettingsMacrosRoute() {
|
|||
{selectedKeyboard.modifierDisplayMap[modifier] || modifier}
|
||||
</span>
|
||||
{idx < step.modifiers.length - 1 && (
|
||||
<span className="text-slate-400 dark:text-slate-600">
|
||||
{" "}
|
||||
+{" "}
|
||||
</span>
|
||||
<span className="text-slate-400 dark:text-slate-600"> + </span>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
|
|
@ -201,10 +193,7 @@ export default function SettingsMacrosRoute() {
|
|||
step.modifiers.length > 0 &&
|
||||
Array.isArray(step.keys) &&
|
||||
step.keys.length > 0 && (
|
||||
<span className="text-slate-400 dark:text-slate-600">
|
||||
{" "}
|
||||
+{" "}
|
||||
</span>
|
||||
<span className="text-slate-400 dark:text-slate-600"> + </span>
|
||||
)}
|
||||
|
||||
{Array.isArray(step.keys) &&
|
||||
|
|
@ -214,17 +203,14 @@ export default function SettingsMacrosRoute() {
|
|||
{selectedKeyboard.keyDisplayMap[key] || key}
|
||||
</span>
|
||||
{idx < step.keys.length - 1 && (
|
||||
<span className="text-slate-400 dark:text-slate-600">
|
||||
{" "}
|
||||
+{" "}
|
||||
</span>
|
||||
<span className="text-slate-400 dark:text-slate-600"> + </span>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<span className="font-medium text-slate-500 dark:text-slate-400">
|
||||
Delay only
|
||||
{m.macros_delay_only()}
|
||||
</span>
|
||||
)}
|
||||
{step.delay !== DEFAULT_DELAY && (
|
||||
|
|
@ -251,7 +237,7 @@ export default function SettingsMacrosRoute() {
|
|||
setShowDeleteConfirm(true);
|
||||
}}
|
||||
disabled={actionLoadingId === macro.id}
|
||||
aria-label={`Delete macro ${macro.name}`}
|
||||
aria-label={m.macros_aria_delete({ name: macro.name })}
|
||||
/>
|
||||
<Button
|
||||
size="XS"
|
||||
|
|
@ -259,16 +245,16 @@ export default function SettingsMacrosRoute() {
|
|||
LeadingIcon={LuCopy}
|
||||
onClick={() => handleDuplicateMacro(macro)}
|
||||
disabled={actionLoadingId === macro.id}
|
||||
aria-label={`Duplicate macro ${macro.name}`}
|
||||
aria-label={m.macros_aria_duplicate({ name: macro.name })}
|
||||
/>
|
||||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
LeadingIcon={LuPenLine}
|
||||
text="Edit"
|
||||
text={m.macros_edit_button()}
|
||||
onClick={() => navigate(`${macro.id}/edit`)}
|
||||
disabled={actionLoadingId === macro.id}
|
||||
aria-label={`Edit macro ${macro.name}`}
|
||||
aria-label={m.macros_aria_edit({ name: macro.name })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -281,10 +267,10 @@ export default function SettingsMacrosRoute() {
|
|||
setShowDeleteConfirm(false);
|
||||
setMacroToDelete(null);
|
||||
}}
|
||||
title="Delete Macro"
|
||||
description={`Are you sure you want to delete "${macroToDelete?.name}"? This action cannot be undone.`}
|
||||
title={m.macros_confirm_delete_title()}
|
||||
description={m.macros_confirm_delete_description({ name: macroToDelete?.name || "" })}
|
||||
variant="danger"
|
||||
confirmText={actionLoadingId === macroToDelete?.id ? "Deleting..." : "Delete"}
|
||||
confirmText={actionLoadingId === macroToDelete?.id ? m.macros_confirm_deleting() : m.macros_delete_confirm_button()}
|
||||
onConfirm={handleDeleteMacro}
|
||||
isConfirming={actionLoadingId === macroToDelete?.id}
|
||||
/>
|
||||
|
|
@ -309,18 +295,18 @@ export default function SettingsMacrosRoute() {
|
|||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<SettingsPageHeader
|
||||
title="Keyboard Macros"
|
||||
description={`Combine keystrokes into a single action for faster workflows.`}
|
||||
title={m.macros_title()}
|
||||
description={m.macros_add_new()}
|
||||
/>
|
||||
{macros.length > 0 && (
|
||||
<div className="flex items-center pl-2">
|
||||
<Button
|
||||
size="SM"
|
||||
theme="primary"
|
||||
text={isMaxMacrosReached ? `Max Reached` : "Add New Macro"}
|
||||
text={isMaxMacrosReached ? m.macros_max_reached() : m.macros_add_new_macro()}
|
||||
onClick={() => navigate("add")}
|
||||
disabled={isMaxMacrosReached}
|
||||
aria-label="Add new macro"
|
||||
aria-label={m.macros_aria_add_new()}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -330,7 +316,7 @@ export default function SettingsMacrosRoute() {
|
|||
{loading && macros.length === 0 ? (
|
||||
<EmptyCard
|
||||
IconElm={LuCommand}
|
||||
headline="Loading macros..."
|
||||
headline={m.macros_loading()}
|
||||
BtnElm={
|
||||
<div className="my-2 flex flex-col items-center space-y-2 text-center">
|
||||
<LoadingSpinner className="h-6 w-6 text-blue-700 dark:text-blue-500" />
|
||||
|
|
@ -340,16 +326,16 @@ export default function SettingsMacrosRoute() {
|
|||
) : macros.length === 0 ? (
|
||||
<EmptyCard
|
||||
IconElm={LuCommand}
|
||||
headline="Create Your First Macro"
|
||||
description="Combine keystrokes into a single action"
|
||||
headline={m.macros_create_first_headline()}
|
||||
description={m.macros_create_first_description()}
|
||||
BtnElm={
|
||||
<Button
|
||||
size="SM"
|
||||
theme="primary"
|
||||
text="Add New Macro"
|
||||
text={m.macros_add_new_macro()}
|
||||
onClick={() => navigate("add")}
|
||||
disabled={isMaxMacrosReached}
|
||||
aria-label="Add new macro"
|
||||
aria-label={m.macros_aria_add_new()}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { KeySequence } from "@hooks/stores";
|
||||
|
||||
export const formatters = {
|
||||
date: (date: Date, options?: Intl.DateTimeFormatOptions) =>
|
||||
new Intl.DateTimeFormat("en-US", {
|
||||
|
|
@ -243,3 +245,10 @@ export function isChromeOS() {
|
|||
/* ChromeOS sets navigator.platform to Linux :/ */
|
||||
return !!navigator.userAgent.match(" CrOS ");
|
||||
}
|
||||
|
||||
export function normalizeSortOrders(macros: KeySequence[]): KeySequence[] {
|
||||
return macros.map((macro, index) => ({
|
||||
...macro,
|
||||
sortOrder: index + 1,
|
||||
}));
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue