mirror of
https://github.com/0PandaDEV/Qopy.git
synced 2025-04-21 13:14:04 +02:00
feat: enhance ActionsMenu component with dynamic action icons, improved keyboard shortcuts, and integrated action handling logic
This commit is contained in:
parent
b828daff08
commit
ddd92a70e2
2 changed files with 310 additions and 48 deletions
|
@ -13,7 +13,7 @@
|
||||||
@click="executeAction(action)" :class="{ selected: isSelected && currentIndex === index }" :ref="(el) => {
|
@click="executeAction(action)" :class="{ selected: isSelected && currentIndex === index }" :ref="(el) => {
|
||||||
if (currentIndex === index) setSelectedElement(el);
|
if (currentIndex === index) setSelectedElement(el);
|
||||||
}
|
}
|
||||||
">
|
" :style="action.color ? { color: action.color } : {}">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<component v-if="action.icon" :is="action.icon" class="icon" />
|
<component v-if="action.icon" :is="action.icon" class="icon" />
|
||||||
<div class="title">{{ action.title }}</div>
|
<div class="title">{{ action.title }}</div>
|
||||||
|
@ -64,8 +64,8 @@
|
||||||
setSelectedElement(el);
|
setSelectedElement(el);
|
||||||
}
|
}
|
||||||
">
|
">
|
||||||
<component v-if="action.icon" :is="action.icon" class="icon" />
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
<component v-if="action.icon" :is="action.icon" class="icon" />
|
||||||
<div class="title">{{ action.title }}</div>
|
<div class="title">{{ action.title }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="action.shortcut" class="shortcut">
|
<div v-if="action.shortcut" class="shortcut">
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
if (currentIndex === getActionIndex(index, 'bottom'))
|
if (currentIndex === getActionIndex(index, 'bottom'))
|
||||||
setSelectedElement(el);
|
setSelectedElement(el);
|
||||||
}
|
}
|
||||||
">
|
" :style="action.color ? { color: action.color } : {}">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<component v-if="action.icon" :is="action.icon" class="icon" />
|
<component v-if="action.icon" :is="action.icon" class="icon" />
|
||||||
<div class="title">{{ action.title }}</div>
|
<div class="title">{{ action.title }}</div>
|
||||||
|
@ -109,16 +109,29 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onUnmounted, computed, watch, nextTick } from "vue";
|
import { ref, onMounted, onUnmounted, computed, watch, nextTick, h } from "vue";
|
||||||
import { OverlayScrollbarsComponent } from "overlayscrollbars-vue";
|
import { OverlayScrollbarsComponent } from "overlayscrollbars-vue";
|
||||||
import "overlayscrollbars/overlayscrollbars.css";
|
import "overlayscrollbars/overlayscrollbars.css";
|
||||||
import Enter from "./Icons/Enter.vue";
|
import Enter from "./Keys/Enter.vue";
|
||||||
import Ctrl from "./Icons/Ctrl.vue";
|
import Cmd from "./Keys/Cmd.vue";
|
||||||
import Cmd from "./Icons/Cmd.vue";
|
import Key from "./Keys/Key.vue";
|
||||||
import Key from "./Icons/Key.vue";
|
|
||||||
import { ContentType, HistoryItem } from "../types/types";
|
import { ContentType, HistoryItem } from "../types/types";
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { useNuxtApp } from "#app";
|
import { useNuxtApp } from "#app";
|
||||||
|
import Shift from "./Keys/Shift.vue";
|
||||||
|
import Gear from "./Icons/Gear.vue";
|
||||||
|
import Bin from "./Icons/Bin.vue";
|
||||||
|
import Pen from "./Icons/Pen.vue";
|
||||||
|
import T from "./Icons/T.vue";
|
||||||
|
import Board from "./Icons/Board.vue";
|
||||||
|
import Cube from "./Icons/Cube.vue";
|
||||||
|
import Open from "./Icons/Open.vue";
|
||||||
|
import Globe from "./Icons/Globe.vue";
|
||||||
|
import Zip from "./Icons/Zip.vue";
|
||||||
|
import Brush from "./Icons/Brush.vue";
|
||||||
|
import Rotate from "./Icons/Rotate.vue";
|
||||||
|
import Expand from "./Icons/Expand.vue";
|
||||||
|
import { useActions } from "../composables/useActions";
|
||||||
|
|
||||||
interface AppInfo {
|
interface AppInfo {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -136,6 +149,7 @@ const menuRef = ref<HTMLElement | null>(null);
|
||||||
const scrollbarsRef = ref<InstanceType<
|
const scrollbarsRef = ref<InstanceType<
|
||||||
typeof OverlayScrollbarsComponent
|
typeof OverlayScrollbarsComponent
|
||||||
> | null>(null);
|
> | null>(null);
|
||||||
|
const { handleAction, isProcessing } = useActions();
|
||||||
|
|
||||||
const SCROLL_PADDING = 8;
|
const SCROLL_PADDING = 8;
|
||||||
|
|
||||||
|
@ -172,136 +186,152 @@ interface ActionItem {
|
||||||
shortcut?: string;
|
shortcut?: string;
|
||||||
icon?: any;
|
icon?: any;
|
||||||
group: string;
|
group: string;
|
||||||
|
color?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const topActions = computed(() => [
|
const topActions = computed((): ActionItem[] => [
|
||||||
{
|
{
|
||||||
title: `Paste to ${currentAppInfo.value.name || "Current App"}`,
|
title: `Paste to ${currentAppInfo.value.name || "Current App"}`,
|
||||||
shortcut: "Enter",
|
shortcut: "Enter",
|
||||||
action: "paste-to-app",
|
action: "paste-to-app",
|
||||||
group: "top",
|
group: "top",
|
||||||
icon: undefined,
|
icon: currentAppInfo.value.icon ? {
|
||||||
|
render() {
|
||||||
|
return h('img', {
|
||||||
|
src: currentAppInfo.value.icon,
|
||||||
|
style: {
|
||||||
|
width: '14px',
|
||||||
|
height: '14px',
|
||||||
|
objectFit: 'contain'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} : Cube,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Copy to Clipboard",
|
title: "Copy to Clipboard",
|
||||||
shortcut: "Ctrl+C",
|
shortcut: "Ctrl+C",
|
||||||
action: "copy",
|
action: "copy",
|
||||||
group: "top",
|
group: "top",
|
||||||
icon: undefined,
|
icon: Board,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const bottomActions = computed(() => [
|
const bottomActions = computed((): ActionItem[] => [
|
||||||
{
|
{
|
||||||
title: "Delete Entry",
|
title: "Delete Entry",
|
||||||
shortcut: "Del",
|
shortcut: "Alt+X",
|
||||||
action: "delete",
|
action: "delete",
|
||||||
group: "bottom",
|
group: "bottom",
|
||||||
icon: undefined,
|
icon: Bin,
|
||||||
|
color: "var(--red)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Delete All Entries",
|
title: "Delete All Entries",
|
||||||
|
shortcut: "Alt+Shift+X",
|
||||||
action: "delete-all",
|
action: "delete-all",
|
||||||
group: "bottom",
|
group: "bottom",
|
||||||
icon: undefined,
|
icon: Bin,
|
||||||
|
color: "var(--red)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Settings",
|
title: "Settings",
|
||||||
|
shortcut: "Ctrl+S",
|
||||||
action: "settings",
|
action: "settings",
|
||||||
group: "bottom",
|
group: "bottom",
|
||||||
icon: undefined,
|
icon: Gear,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const textActions = computed(() => [
|
const textActions = computed((): ActionItem[] => [
|
||||||
{
|
{
|
||||||
title: "Paste as plain text",
|
title: "Paste as plain text",
|
||||||
action: "paste-plain",
|
action: "paste-plain",
|
||||||
shortcut: "",
|
shortcut: "Ctrl+Shift+V",
|
||||||
group: "text",
|
group: "text",
|
||||||
icon: undefined,
|
icon: T,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Edit text",
|
title: "Edit text",
|
||||||
action: "edit-text",
|
action: "edit-text",
|
||||||
shortcut: "",
|
shortcut: "Ctrl+E",
|
||||||
group: "text",
|
group: "text",
|
||||||
icon: undefined,
|
icon: Pen,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const imageActions = computed(() => [
|
const imageActions = computed((): ActionItem[] => [
|
||||||
{
|
{
|
||||||
title: "Rotate",
|
title: "Rotate",
|
||||||
action: "rotate-image",
|
action: "rotate-image",
|
||||||
shortcut: "",
|
shortcut: "Alt+R",
|
||||||
group: "image",
|
group: "image",
|
||||||
icon: undefined,
|
icon: Rotate,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Resize",
|
title: "Resize",
|
||||||
action: "resize-image",
|
action: "resize-image",
|
||||||
shortcut: "",
|
shortcut: "Alt+S",
|
||||||
group: "image",
|
group: "image",
|
||||||
icon: undefined,
|
icon: Expand,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Compress",
|
title: "Compress",
|
||||||
action: "compress-image",
|
action: "compress-image",
|
||||||
shortcut: "",
|
shortcut: "Alt+C",
|
||||||
group: "image",
|
group: "image",
|
||||||
icon: undefined,
|
icon: Zip,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const fileActions = computed(() => [
|
const fileActions = computed((): ActionItem[] => [
|
||||||
{
|
{
|
||||||
title: "Open",
|
title: "Open",
|
||||||
action: "open-file",
|
action: "open-file",
|
||||||
shortcut: "",
|
shortcut: "Ctrl+O",
|
||||||
group: "file",
|
group: "file",
|
||||||
icon: undefined,
|
icon: Open,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Compress to zip/7z",
|
title: "Compress to zip",
|
||||||
action: "compress-file",
|
action: "compress-file",
|
||||||
shortcut: "",
|
shortcut: "Alt+C",
|
||||||
group: "file",
|
group: "file",
|
||||||
icon: undefined,
|
icon: Zip,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const linkActions = computed(() => [
|
const linkActions = computed((): ActionItem[] => [
|
||||||
{
|
{
|
||||||
title: "Open in Browser",
|
title: "Open in Browser",
|
||||||
action: "open-link",
|
action: "open-link",
|
||||||
shortcut: "",
|
shortcut: "Ctrl+O",
|
||||||
group: "link",
|
group: "link",
|
||||||
icon: undefined,
|
icon: Globe,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const colorActions = computed(() => [
|
const colorActions = computed((): ActionItem[] => [
|
||||||
{
|
{
|
||||||
title: "Copy as HEX",
|
title: "Copy as HEX",
|
||||||
action: "copy-hex",
|
action: "copy-hex",
|
||||||
shortcut: "",
|
shortcut: "Alt+H",
|
||||||
group: "color",
|
group: "color",
|
||||||
icon: undefined,
|
icon: Brush,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Copy as RGB(a)",
|
title: "Copy as RGB(a)",
|
||||||
action: "copy-rgba",
|
action: "copy-rgba",
|
||||||
shortcut: "",
|
shortcut: "Alt+R",
|
||||||
group: "color",
|
group: "color",
|
||||||
icon: undefined,
|
icon: Brush,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Copy as HSL(a)",
|
title: "Copy as HSL(a)",
|
||||||
action: "copy-hsla",
|
action: "copy-hsla",
|
||||||
shortcut: "",
|
shortcut: "Alt+S",
|
||||||
group: "color",
|
group: "color",
|
||||||
icon: undefined,
|
icon: Brush,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -369,10 +399,10 @@ const parseShortcut = (shortcut: string): KeyPart[] => {
|
||||||
const trimmedPart = part.trim();
|
const trimmedPart = part.trim();
|
||||||
let keyPart: KeyPart;
|
let keyPart: KeyPart;
|
||||||
|
|
||||||
if (trimmedPart.toLowerCase() === "ctrl") {
|
if (trimmedPart.toLowerCase() === "cmd") {
|
||||||
keyPart = { type: "modifier", value: trimmedPart, component: Ctrl };
|
|
||||||
} else if (trimmedPart.toLowerCase() === "cmd") {
|
|
||||||
keyPart = { type: "modifier", value: trimmedPart, component: Cmd };
|
keyPart = { type: "modifier", value: trimmedPart, component: Cmd };
|
||||||
|
} else if (trimmedPart.toLowerCase() === "shift") {
|
||||||
|
keyPart = { type: "modifier", value: trimmedPart, component: Shift };
|
||||||
} else if (trimmedPart.toLowerCase() === "enter") {
|
} else if (trimmedPart.toLowerCase() === "enter") {
|
||||||
keyPart = { type: "key", value: trimmedPart, component: Enter };
|
keyPart = { type: "key", value: trimmedPart, component: Enter };
|
||||||
} else {
|
} else {
|
||||||
|
@ -391,7 +421,7 @@ const parseShortcut = (shortcut: string): KeyPart[] => {
|
||||||
|
|
||||||
const executeAction = (action: ActionItem) => {
|
const executeAction = (action: ActionItem) => {
|
||||||
emit("close");
|
emit("close");
|
||||||
emit("action", action.action, props.selectedItem);
|
handleAction(action.action, props.selectedItem);
|
||||||
};
|
};
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
|
@ -404,6 +434,10 @@ const handleClickOutside = (event: MouseEvent) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleWindowBlur = () => {
|
||||||
|
close();
|
||||||
|
};
|
||||||
|
|
||||||
const setupKeyboardHandlers = () => {
|
const setupKeyboardHandlers = () => {
|
||||||
$keyboard.on(
|
$keyboard.on(
|
||||||
"actionsMenu",
|
"actionsMenu",
|
||||||
|
@ -603,11 +637,13 @@ watch(
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.addEventListener("click", handleClickOutside);
|
document.addEventListener("click", handleClickOutside);
|
||||||
|
window.addEventListener("blur", handleWindowBlur);
|
||||||
getAppInfo();
|
getAppInfo();
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
document.removeEventListener("click", handleClickOutside);
|
document.removeEventListener("click", handleClickOutside);
|
||||||
|
window.removeEventListener("blur", handleWindowBlur);
|
||||||
$keyboard.disableContext("actionsMenu");
|
$keyboard.disableContext("actionsMenu");
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -683,6 +719,10 @@ onUnmounted(() => {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
222
composables/useActions.ts
Normal file
222
composables/useActions.ts
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
|
import { HistoryItem } from "../types/types";
|
||||||
|
|
||||||
|
const { $history } = useNuxtApp();
|
||||||
|
const { hideApp } = useAppControl();
|
||||||
|
|
||||||
|
export function useActions() {
|
||||||
|
const isProcessing = ref(false);
|
||||||
|
|
||||||
|
const handleAction = async (action: string, item?: HistoryItem) => {
|
||||||
|
if (!item && action !== "settings" && action !== "delete-all") return;
|
||||||
|
|
||||||
|
isProcessing.value = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (action) {
|
||||||
|
case "paste-to-app":
|
||||||
|
await pasteToCurrentApp(item);
|
||||||
|
break;
|
||||||
|
case "copy":
|
||||||
|
// await copyToClipboard(item);
|
||||||
|
break;
|
||||||
|
case "delete":
|
||||||
|
await deleteEntry(item);
|
||||||
|
break;
|
||||||
|
case "delete-all":
|
||||||
|
// await deleteAllEntries();
|
||||||
|
break;
|
||||||
|
case "settings":
|
||||||
|
openSettings();
|
||||||
|
break;
|
||||||
|
case "paste-plain":
|
||||||
|
// await pasteAsPlainText(item);
|
||||||
|
break;
|
||||||
|
case "edit-text":
|
||||||
|
// openTextEditor(item);
|
||||||
|
break;
|
||||||
|
case "rotate-image":
|
||||||
|
// await rotateImage(item);
|
||||||
|
break;
|
||||||
|
case "resize-image":
|
||||||
|
// openImageResizer(item);
|
||||||
|
break;
|
||||||
|
case "compress-image":
|
||||||
|
// await compressImage(item);
|
||||||
|
break;
|
||||||
|
case "open-file":
|
||||||
|
// await openFile(item);
|
||||||
|
break;
|
||||||
|
case "compress-file":
|
||||||
|
// await compressFile(item);
|
||||||
|
break;
|
||||||
|
case "open-link":
|
||||||
|
// await openInBrowser(item);
|
||||||
|
break;
|
||||||
|
case "copy-hex":
|
||||||
|
// await copyColorFormat(item, "hex");
|
||||||
|
break;
|
||||||
|
case "copy-rgba":
|
||||||
|
// await copyColorFormat(item, "rgba");
|
||||||
|
break;
|
||||||
|
case "copy-hsla":
|
||||||
|
// await copyColorFormat(item, "hsla");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn(`Action ${action} not implemented`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error executing action ${action}:`, error);
|
||||||
|
} finally {
|
||||||
|
isProcessing.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const pasteToCurrentApp = async (item?: HistoryItem) => {
|
||||||
|
if (!item) return;
|
||||||
|
|
||||||
|
let content = item.content;
|
||||||
|
let contentType: string = item.content_type;
|
||||||
|
if (contentType === "image") {
|
||||||
|
try {
|
||||||
|
content = await $history.readImage({ filename: content });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error reading image file:", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await hideApp();
|
||||||
|
await $history.writeAndPaste({ content, contentType });
|
||||||
|
};
|
||||||
|
|
||||||
|
// const copyToClipboard = async (item?: HistoryItem) => {
|
||||||
|
// if (!item) return;
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// switch (item.content_type) {
|
||||||
|
// case ContentType.Text:
|
||||||
|
// case ContentType.Link:
|
||||||
|
// case ContentType.Code:
|
||||||
|
// await writeText(item.content);
|
||||||
|
// break;
|
||||||
|
// case ContentType.Image:
|
||||||
|
// await invoke("copy_image_to_clipboard", { path: item.file_path });
|
||||||
|
// break;
|
||||||
|
// case ContentType.File:
|
||||||
|
// await invoke("copy_file_reference", { path: item.file_path });
|
||||||
|
// break;
|
||||||
|
// case ContentType.Color:
|
||||||
|
// await writeText(item.content);
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// console.warn(`Copying type ${item.content_type} not implemented`);
|
||||||
|
// }
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error("Failed to copy to clipboard:", error);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
const deleteEntry = async (item?: HistoryItem) => {
|
||||||
|
if (!item) return;
|
||||||
|
try {
|
||||||
|
await invoke("delete_history_item", { id: item.id });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to delete entry:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// const deleteAllEntries = async () => {
|
||||||
|
// try {
|
||||||
|
// await invoke('delete_all_history');
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error('Failed to delete all entries:', error);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
const openSettings = () => {
|
||||||
|
navigateTo("/settings");
|
||||||
|
};
|
||||||
|
|
||||||
|
// const pasteAsPlainText = async (item?: HistoryItem) => {
|
||||||
|
// if (!item) return;
|
||||||
|
// try {
|
||||||
|
// await invoke('paste_as_plain_text', { content: item.content });
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error('Failed to paste as plain text:', error);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const openTextEditor = (item?: HistoryItem) => {
|
||||||
|
// if (!item) return;
|
||||||
|
// // Implement logic to open text editor with the content
|
||||||
|
// // This might use Nuxt router or a modal based on your app architecture
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const rotateImage = async (item?: HistoryItem) => {
|
||||||
|
// if (!item || item.content_type !== ContentType.Image) return;
|
||||||
|
// try {
|
||||||
|
// await invoke('rotate_image', { path: item.file_path });
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error('Failed to rotate image:', error);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const openImageResizer = (item?: HistoryItem) => {
|
||||||
|
// if (!item || item.content_type !== ContentType.Image) return;
|
||||||
|
// // Implement logic to open image resizer UI for this image
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const compressImage = async (item?: HistoryItem) => {
|
||||||
|
// if (!item || item.content_type !== ContentType.Image) return;
|
||||||
|
// try {
|
||||||
|
// await invoke('compress_image', { path: item.file_path });
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error('Failed to compress image:', error);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const openFile = async (item?: HistoryItem) => {
|
||||||
|
// if (!item || item.content_type !== ContentType.File) return;
|
||||||
|
// try {
|
||||||
|
// await invoke('open_file', { path: item.file_path });
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error('Failed to open file:', error);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const compressFile = async (item?: HistoryItem) => {
|
||||||
|
// if (!item || item.content_type !== ContentType.File) return;
|
||||||
|
// try {
|
||||||
|
// await invoke('compress_file', { path: item.file_path });
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error('Failed to compress file:', error);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const openInBrowser = async (item?: HistoryItem) => {
|
||||||
|
// if (!item || item.content_type !== ContentType.Link) return;
|
||||||
|
// try {
|
||||||
|
// await invoke('open_url', { url: item.content });
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error('Failed to open URL in browser:', error);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const copyColorFormat = async (item?: HistoryItem, format: 'hex' | 'rgba' | 'hsla' = 'hex') => {
|
||||||
|
// if (!item || item.content_type !== ContentType.Color) return;
|
||||||
|
// try {
|
||||||
|
// const formattedColor = await invoke('get_color_format', {
|
||||||
|
// color: item.content,
|
||||||
|
// format
|
||||||
|
// });
|
||||||
|
// await writeText(formattedColor as string);
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error(`Failed to copy color as ${format}:`, error);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleAction,
|
||||||
|
isProcessing,
|
||||||
|
};
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue