mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-29 22:01:03 +00:00
feat: adding motion
This commit is contained in:
@@ -57,6 +57,7 @@
|
|||||||
"electron-log": "^5.2.4",
|
"electron-log": "^5.2.4",
|
||||||
"electron-updater": "^6.6.2",
|
"electron-updater": "^6.6.2",
|
||||||
"file-type": "^20.5.0",
|
"file-type": "^20.5.0",
|
||||||
|
"framer-motion": "^12.15.0",
|
||||||
"i18next": "^23.11.2",
|
"i18next": "^23.11.2",
|
||||||
"i18next-browser-languagedetector": "^7.2.1",
|
"i18next-browser-languagedetector": "^7.2.1",
|
||||||
"jsdom": "^24.0.0",
|
"jsdom": "^24.0.0",
|
||||||
|
|||||||
@@ -217,7 +217,9 @@
|
|||||||
"freeze_backup": "Pin it so it's not overwritten by automatic backups",
|
"freeze_backup": "Pin it so it's not overwritten by automatic backups",
|
||||||
"unfreeze_backup": "Unpin it",
|
"unfreeze_backup": "Unpin it",
|
||||||
"backup_frozen": "Backup pinned",
|
"backup_frozen": "Backup pinned",
|
||||||
"backup_unfrozen": "Backup unpinned"
|
"backup_unfrozen": "Backup unpinned",
|
||||||
|
"backup_freeze_failed": "Failed to freeze backup",
|
||||||
|
"backup_freeze_failed_description": "You must leave at least one free slot for automatic backups"
|
||||||
},
|
},
|
||||||
"activation": {
|
"activation": {
|
||||||
"title": "Activate Hydra",
|
"title": "Activate Hydra",
|
||||||
|
|||||||
@@ -204,7 +204,9 @@
|
|||||||
"freeze_backup": "Fixar para não ser apagado por backups automáticos",
|
"freeze_backup": "Fixar para não ser apagado por backups automáticos",
|
||||||
"unfreeze_backup": "Remover dos fixados",
|
"unfreeze_backup": "Remover dos fixados",
|
||||||
"backup_frozen": "Backup fixado",
|
"backup_frozen": "Backup fixado",
|
||||||
"backup_unfrozen": "Backup removido dos fixados"
|
"backup_unfrozen": "Backup removido dos fixados",
|
||||||
|
"backup_freeze_failed": "Falha ao fixar backup",
|
||||||
|
"backup_freeze_failed_description": "Você deve deixar pelo menos um espaço livre para backups automáticos"
|
||||||
},
|
},
|
||||||
"activation": {
|
"activation": {
|
||||||
"title": "Ativação",
|
"title": "Ativação",
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ export function CloudSyncContextProvider({
|
|||||||
getGameArtifacts();
|
getGameArtifacts();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error("Failed to toggle artifact freeze", objectId, shop, err);
|
logger.error("Failed to toggle artifact freeze", objectId, shop, err);
|
||||||
|
throw err;
|
||||||
} finally {
|
} finally {
|
||||||
setFreezingArtifact(false);
|
setFreezingArtifact(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Button, Modal, ModalProps } from "@renderer/components";
|
import { Button, Modal, ModalProps } from "@renderer/components";
|
||||||
import { useContext, useEffect, useMemo, useState } from "react";
|
import { useContext, useEffect, useMemo, useState } from "react";
|
||||||
import { cloudSyncContext, gameDetailsContext } from "@renderer/context";
|
import { cloudSyncContext, gameDetailsContext } from "@renderer/context";
|
||||||
|
|
||||||
import "./cloud-sync-modal.scss";
|
import "./cloud-sync-modal.scss";
|
||||||
import { formatBytes } from "@shared";
|
import { formatBytes } from "@shared";
|
||||||
import {
|
import {
|
||||||
@@ -22,6 +21,8 @@ import { AxiosProgressEvent } from "axios";
|
|||||||
import { formatDownloadProgress } from "@renderer/helpers";
|
import { formatDownloadProgress } from "@renderer/helpers";
|
||||||
import { CloudSyncRenameArtifactModal } from "../cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal";
|
import { CloudSyncRenameArtifactModal } from "../cloud-sync-rename-artifact-modal/cloud-sync-rename-artifact-modal";
|
||||||
import { GameArtifact } from "@types";
|
import { GameArtifact } from "@types";
|
||||||
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
|
import { orderBy } from "lodash-es";
|
||||||
|
|
||||||
export interface CloudSyncModalProps
|
export interface CloudSyncModalProps
|
||||||
extends Omit<ModalProps, "children" | "title"> {}
|
extends Omit<ModalProps, "children" | "title"> {}
|
||||||
@@ -35,7 +36,6 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { t } = useTranslation("game_details");
|
const { t } = useTranslation("game_details");
|
||||||
|
|
||||||
const { formatDate, formatDateTime } = useDate();
|
const { formatDate, formatDateTime } = useDate();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -60,10 +60,8 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
|||||||
|
|
||||||
const handleDeleteArtifactClick = async (gameArtifactId: string) => {
|
const handleDeleteArtifactClick = async (gameArtifactId: string) => {
|
||||||
setDeletingArtifact(true);
|
setDeletingArtifact(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await deleteGameArtifact(gameArtifactId);
|
await deleteGameArtifact(gameArtifactId);
|
||||||
|
|
||||||
showSuccessToast(t("backup_deleted"));
|
showSuccessToast(t("backup_deleted"));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorToast("backup_deletion_failed");
|
showErrorToast("backup_deletion_failed");
|
||||||
@@ -81,7 +79,6 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
|||||||
setBackupDownloadProgress(progressEvent);
|
setBackupDownloadProgress(progressEvent);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
removeBackupDownloadProgressListener();
|
removeBackupDownloadProgressListener();
|
||||||
};
|
};
|
||||||
@@ -96,12 +93,14 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
|||||||
artifactId: string,
|
artifactId: string,
|
||||||
isFrozen: boolean
|
isFrozen: boolean
|
||||||
) => {
|
) => {
|
||||||
await toggleArtifactFreeze(artifactId, isFrozen);
|
try {
|
||||||
|
await toggleArtifactFreeze(artifactId, isFrozen);
|
||||||
if (isFrozen) {
|
showSuccessToast(isFrozen ? t("backup_frozen") : t("backup_unfrozen"));
|
||||||
showSuccessToast(t("backup_frozen"));
|
} catch (err) {
|
||||||
} else {
|
showErrorToast(
|
||||||
showSuccessToast(t("backup_unfrozen"));
|
t("backup_freeze_failed"),
|
||||||
|
t("backup_freeze_failed_description")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -123,7 +122,6 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (restoringBackup) {
|
if (restoringBackup) {
|
||||||
return (
|
return (
|
||||||
<span className="cloud-sync-modal__backup-state-label">
|
<span className="cloud-sync-modal__backup-state-label">
|
||||||
@@ -136,7 +134,6 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadingPreview) {
|
if (loadingPreview) {
|
||||||
return (
|
return (
|
||||||
<span className="cloud-sync-modal__backup-state-label">
|
<span className="cloud-sync-modal__backup-state-label">
|
||||||
@@ -145,19 +142,15 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (artifacts.length >= backupsPerGameLimit) {
|
if (artifacts.length >= backupsPerGameLimit) {
|
||||||
return t("max_number_of_artifacts_reached");
|
return t("max_number_of_artifacts_reached");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!backupPreview) {
|
if (!backupPreview) {
|
||||||
return t("no_backup_preview");
|
return t("no_backup_preview");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (artifacts.length === 0) {
|
if (artifacts.length === 0) {
|
||||||
return t("no_backups");
|
return t("no_backups");
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}, [
|
}, [
|
||||||
uploadingBackup,
|
uploadingBackup,
|
||||||
@@ -194,7 +187,6 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
|||||||
<div className="cloud-sync-modal__title-container">
|
<div className="cloud-sync-modal__title-container">
|
||||||
<h2>{gameTitle}</h2>
|
<h2>{gameTitle}</h2>
|
||||||
<p>{backupStateLabel}</p>
|
<p>{backupStateLabel}</p>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="cloud-sync-modal__manage-files-button"
|
className="cloud-sync-modal__manage-files-button"
|
||||||
@@ -235,83 +227,99 @@ export function CloudSyncModal({ visible, onClose }: CloudSyncModalProps) {
|
|||||||
|
|
||||||
{artifacts.length > 0 ? (
|
{artifacts.length > 0 ? (
|
||||||
<ul className="cloud-sync-modal__artifacts">
|
<ul className="cloud-sync-modal__artifacts">
|
||||||
{artifacts.map((artifact) => (
|
<AnimatePresence>
|
||||||
<li key={artifact.id} className="cloud-sync-modal__artifact">
|
{orderBy(artifacts, [(a) => !a.isFrozen], ["asc"]).map(
|
||||||
<div className="cloud-sync-modal__artifact-info">
|
(artifact) => (
|
||||||
<div className="cloud-sync-modal__artifact-header">
|
<motion.li
|
||||||
<button
|
key={artifact.id}
|
||||||
type="button"
|
className="cloud-sync-modal__artifact"
|
||||||
className="cloud-sync-modal__artifact-label"
|
layout
|
||||||
onClick={() => setArtifactToRename(artifact)}
|
initial={{ opacity: 0, y: 10 }}
|
||||||
>
|
animate={{ opacity: 1, y: 0 }}
|
||||||
{artifact.label ??
|
exit={{ opacity: 0, y: -10 }}
|
||||||
t("backup_from", {
|
transition={{ duration: 0.2 }}
|
||||||
date: formatDate(artifact.createdAt),
|
|
||||||
})}
|
|
||||||
|
|
||||||
<PencilIcon />
|
|
||||||
</button>
|
|
||||||
<small>{formatBytes(artifact.artifactLengthInBytes)}</small>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span className="cloud-sync-modal__artifact-meta">
|
|
||||||
<DeviceDesktopIcon size={14} />
|
|
||||||
{artifact.hostname}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span className="cloud-sync-modal__artifact-meta">
|
|
||||||
<InfoIcon size={14} />
|
|
||||||
{artifact.downloadOptionTitle ??
|
|
||||||
t("no_download_option_info")}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span className="cloud-sync-modal__artifact-meta">
|
|
||||||
<ClockIcon size={14} />
|
|
||||||
{formatDateTime(artifact.createdAt)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="cloud-sync-modal__artifact-actions">
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
tooltip={
|
|
||||||
artifact.isFrozen
|
|
||||||
? t("unfreeze_backup")
|
|
||||||
: t("freeze_backup")
|
|
||||||
}
|
|
||||||
theme={artifact.isFrozen ? "primary" : "outline"}
|
|
||||||
onClick={() =>
|
|
||||||
handleFreezeArtifactClick(artifact.id, !artifact.isFrozen)
|
|
||||||
}
|
|
||||||
disabled={disableActions}
|
|
||||||
>
|
>
|
||||||
{artifact.isFrozen ? <PinSlashIcon /> : <PinIcon />}
|
<div className="cloud-sync-modal__artifact-info">
|
||||||
</Button>
|
<div className="cloud-sync-modal__artifact-header">
|
||||||
<Button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleBackupInstallClick(artifact.id)}
|
className="cloud-sync-modal__artifact-label"
|
||||||
disabled={disableActions}
|
onClick={() => setArtifactToRename(artifact)}
|
||||||
theme="outline"
|
>
|
||||||
>
|
{artifact.label ??
|
||||||
{restoringBackup ? (
|
t("backup_from", {
|
||||||
<SyncIcon className="cloud-sync-modal__sync-icon" />
|
date: formatDate(artifact.createdAt),
|
||||||
) : (
|
})}
|
||||||
<HistoryIcon />
|
<PencilIcon />
|
||||||
)}
|
</button>
|
||||||
{t("install_backup")}
|
<small>
|
||||||
</Button>
|
{formatBytes(artifact.artifactLengthInBytes)}
|
||||||
<Button
|
</small>
|
||||||
type="button"
|
</div>
|
||||||
onClick={() => handleDeleteArtifactClick(artifact.id)}
|
|
||||||
disabled={disableActions || artifact.isFrozen}
|
<span className="cloud-sync-modal__artifact-meta">
|
||||||
theme="outline"
|
<DeviceDesktopIcon size={14} />
|
||||||
tooltip={t("delete_backup")}
|
{artifact.hostname}
|
||||||
>
|
</span>
|
||||||
<TrashIcon />
|
|
||||||
</Button>
|
<span className="cloud-sync-modal__artifact-meta">
|
||||||
</div>
|
<InfoIcon size={14} />
|
||||||
</li>
|
{artifact.downloadOptionTitle ??
|
||||||
))}
|
t("no_download_option_info")}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span className="cloud-sync-modal__artifact-meta">
|
||||||
|
<ClockIcon size={14} />
|
||||||
|
{formatDateTime(artifact.createdAt)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="cloud-sync-modal__artifact-actions">
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
tooltip={
|
||||||
|
artifact.isFrozen
|
||||||
|
? t("unfreeze_backup")
|
||||||
|
: t("freeze_backup")
|
||||||
|
}
|
||||||
|
theme={artifact.isFrozen ? "primary" : "outline"}
|
||||||
|
onClick={() =>
|
||||||
|
handleFreezeArtifactClick(
|
||||||
|
artifact.id,
|
||||||
|
!artifact.isFrozen
|
||||||
|
)
|
||||||
|
}
|
||||||
|
disabled={disableActions}
|
||||||
|
>
|
||||||
|
{artifact.isFrozen ? <PinSlashIcon /> : <PinIcon />}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleBackupInstallClick(artifact.id)}
|
||||||
|
disabled={disableActions}
|
||||||
|
theme="outline"
|
||||||
|
>
|
||||||
|
{restoringBackup ? (
|
||||||
|
<SyncIcon className="cloud-sync-modal__sync-icon" />
|
||||||
|
) : (
|
||||||
|
<HistoryIcon />
|
||||||
|
)}
|
||||||
|
{t("install_backup")}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleDeleteArtifactClick(artifact.id)}
|
||||||
|
disabled={disableActions || artifact.isFrozen}
|
||||||
|
theme="outline"
|
||||||
|
tooltip={t("delete_backup")}
|
||||||
|
>
|
||||||
|
<TrashIcon />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</motion.li>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
</ul>
|
</ul>
|
||||||
) : (
|
) : (
|
||||||
<p>{t("no_backups_created")}</p>
|
<p>{t("no_backups_created")}</p>
|
||||||
|
|||||||
23
yarn.lock
23
yarn.lock
@@ -5646,6 +5646,15 @@ formdata-polyfill@^4.0.10:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fetch-blob "^3.1.2"
|
fetch-blob "^3.1.2"
|
||||||
|
|
||||||
|
framer-motion@^12.15.0:
|
||||||
|
version "12.15.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-12.15.0.tgz#6892283fc7967b071f537d6d160ab49e3d5e73ae"
|
||||||
|
integrity sha512-XKg/LnKExdLGugZrDILV7jZjI599785lDIJZLxMiiIFidCsy0a4R2ZEf+Izm67zyOuJgQYTHOmodi7igQsw3vg==
|
||||||
|
dependencies:
|
||||||
|
motion-dom "^12.15.0"
|
||||||
|
motion-utils "^12.12.1"
|
||||||
|
tslib "^2.4.0"
|
||||||
|
|
||||||
fs-extra@^10.0.0, fs-extra@^10.1.0:
|
fs-extra@^10.0.0, fs-extra@^10.1.0:
|
||||||
version "10.1.0"
|
version "10.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
|
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
|
||||||
@@ -7304,6 +7313,18 @@ module-error@^1.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86"
|
resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86"
|
||||||
integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==
|
integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==
|
||||||
|
|
||||||
|
motion-dom@^12.15.0:
|
||||||
|
version "12.15.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/motion-dom/-/motion-dom-12.15.0.tgz#eca7c9d8c28976b8c920f175f92d5288f5a17785"
|
||||||
|
integrity sha512-D2ldJgor+2vdcrDtKJw48k3OddXiZN1dDLLWrS8kiHzQdYVruh0IoTwbJBslrnTXIPgFED7PBN2Zbwl7rNqnhA==
|
||||||
|
dependencies:
|
||||||
|
motion-utils "^12.12.1"
|
||||||
|
|
||||||
|
motion-utils@^12.12.1:
|
||||||
|
version "12.12.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/motion-utils/-/motion-utils-12.12.1.tgz#63e28751325cb9d1cd684f3c273a570022b0010e"
|
||||||
|
integrity sha512-f9qiqUHm7hWSLlNW8gS9pisnsN7CRFRD58vNjptKdsqFLpkVnX00TNeD6Q0d27V9KzT7ySFyK1TZ/DShfVOv6w==
|
||||||
|
|
||||||
ms@^2.0.0, ms@^2.1.1, ms@^2.1.3:
|
ms@^2.0.0, ms@^2.1.1, ms@^2.1.3:
|
||||||
version "2.1.3"
|
version "2.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
||||||
@@ -9041,7 +9062,7 @@ ts-node@^10.9.2:
|
|||||||
v8-compile-cache-lib "^3.0.1"
|
v8-compile-cache-lib "^3.0.1"
|
||||||
yn "3.1.1"
|
yn "3.1.1"
|
||||||
|
|
||||||
tslib@^2.0.0, tslib@^2.1.0:
|
tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0:
|
||||||
version "2.8.1"
|
version "2.8.1"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
||||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||||
|
|||||||
Reference in New Issue
Block a user