mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
Revert "More friendly experience when presenting repack options"
This commit is contained in:
parent
e5fec91062
commit
2cb76a9ad4
32 changed files with 16 additions and 794 deletions
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-sprout"><path d="M7 20h10"/><path d="M10 20c5.5-2.5.8-6.4 3-10"/><path d="M9.5 9.4c1.1.8 1.8 2.2 2.3 3.7-2 .4-3.5.4-4.8-.3-1.2-.6-2.3-1.9-3-4.2 2.8-.5 4.4 0 5.5.8z"/><path d="M14.1 6a7 7 0 0 0-1.1 4c1.9-.1 3.3-.6 4.3-1.4 1-1 1.6-2.3 1.7-4.6-2.7.1-4 1-4.9 2z"/></svg>
|
Before Width: | Height: | Size: 469 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-users"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
|
Before Width: | Height: | Size: 373 B |
|
@ -8,4 +8,3 @@ export * from "./sidebar/sidebar";
|
|||
export * from "./text-field/text-field";
|
||||
export * from "./checkbox-field/checkbox-field";
|
||||
export * from "./link/link";
|
||||
export * from "./tag/tag";
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
import { SPACING_UNIT, vars } from "../../theme.css";
|
||||
import { style } from "@vanilla-extract/css";
|
||||
|
||||
export const tagStyle = style({
|
||||
borderRadius: "3px",
|
||||
border: `1px solid ${vars.color.border}`,
|
||||
padding: `${SPACING_UNIT / 4}px ${SPACING_UNIT}px`,
|
||||
});
|
||||
|
||||
export const tagText = style({
|
||||
fontSize: "11px",
|
||||
});
|
|
@ -1,9 +0,0 @@
|
|||
import * as styles from "./tag.css";
|
||||
|
||||
export function Tag({ children }: Readonly<{ children: React.ReactNode }>) {
|
||||
return (
|
||||
<div className={styles.tagStyle}>
|
||||
<span className={styles.tagText}>{children}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
import { style } from "@vanilla-extract/css";
|
||||
|
||||
export const tooltipStyle = style({
|
||||
position: "relative",
|
||||
display: "flex",
|
||||
cursor: "pointer",
|
||||
alignItems: "center",
|
||||
});
|
||||
|
||||
export const tooltipTextStyle = style({
|
||||
visibility: "hidden",
|
||||
backgroundColor: "#555",
|
||||
color: "#fff",
|
||||
textAlign: "center",
|
||||
borderRadius: "6px",
|
||||
padding: "5px 5px",
|
||||
position: "absolute",
|
||||
zIndex: "1",
|
||||
bottom: "125%",
|
||||
left: "max(0%, min(100%, 50%))",
|
||||
transform: "translateX(-50%)",
|
||||
":after": {
|
||||
content: '""',
|
||||
position: "absolute",
|
||||
top: "100%",
|
||||
left: "50%",
|
||||
marginLeft: "-5px",
|
||||
borderWidth: "5px",
|
||||
borderStyle: "solid",
|
||||
borderColor: "#555 transparent transparent transparent",
|
||||
},
|
||||
});
|
||||
|
||||
export const tooltipVisible = style({
|
||||
visibility: "visible",
|
||||
});
|
|
@ -1,26 +0,0 @@
|
|||
import { useState } from "react";
|
||||
import * as styles from "./tooltip.css";
|
||||
|
||||
interface TooltipProps {
|
||||
children: React.ReactNode;
|
||||
tooltipText: string;
|
||||
}
|
||||
|
||||
export function Tooltip({ children, tooltipText }: Readonly<TooltipProps>) {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={styles.tooltipStyle}
|
||||
onMouseEnter={() => setIsVisible(true)}
|
||||
onMouseLeave={() => setIsVisible(false)}
|
||||
>
|
||||
{children}
|
||||
<span
|
||||
className={`${styles.tooltipTextStyle} ${isVisible ? styles.tooltipVisible : ""}`}
|
||||
>
|
||||
{tooltipText}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
3
src/renderer/src/declaration.d.ts
vendored
3
src/renderer/src/declaration.d.ts
vendored
|
@ -90,9 +90,6 @@ declare global {
|
|||
options: Electron.OpenDialogOptions
|
||||
) => Promise<Electron.OpenDialogReturnValue>;
|
||||
platform: NodeJS.Platform;
|
||||
getMagnetHealth: (
|
||||
magnet: string
|
||||
) => Promise<{ seeders: number; peers: number }>;
|
||||
}
|
||||
|
||||
interface Window {
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
import { toCapitalize } from "./string";
|
||||
|
||||
export const isMultiplayerRepack = (title: string, repacker: string) => {
|
||||
const titleToLower = title.toLowerCase();
|
||||
const repackerToLower = repacker.toLowerCase();
|
||||
|
||||
return (
|
||||
titleToLower.includes("multiplayer") ||
|
||||
titleToLower.includes("onlinefix") ||
|
||||
titleToLower.includes("online fix") ||
|
||||
repackerToLower.includes("onlinefix") ||
|
||||
repackerToLower.includes("online fix")
|
||||
);
|
||||
};
|
||||
|
||||
export const supportMultiLanguage = (title: string) => {
|
||||
const multiFollowedByDigitsRegex = /multi\d+/;
|
||||
|
||||
return multiFollowedByDigitsRegex.test(title.toLowerCase());
|
||||
};
|
||||
|
||||
export const getRepackLanguageBasedOnRepacker = (
|
||||
repacker: string,
|
||||
userLanguage: string
|
||||
) => {
|
||||
const languageCodes = {
|
||||
xatab: "ru",
|
||||
};
|
||||
|
||||
const languageCode = languageCodes[repacker.toLowerCase()] || "en";
|
||||
|
||||
const displayNames = new Intl.DisplayNames([userLanguage], {
|
||||
type: "language",
|
||||
});
|
||||
|
||||
const language = displayNames.of(languageCode);
|
||||
|
||||
return language ? toCapitalize(language) : "English";
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
export function toCapitalize(str: string) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
|
@ -16,9 +16,3 @@ export const repackButton = style({
|
|||
color: vars.color.bodyText,
|
||||
padding: `${SPACING_UNIT * 2}px`,
|
||||
});
|
||||
|
||||
export const tagsContainer = style({
|
||||
display: "flex",
|
||||
gap: `${SPACING_UNIT}px`,
|
||||
flexWrap: "wrap",
|
||||
});
|
||||
|
|
|
@ -9,14 +9,6 @@ import * as styles from "./repacks-modal.css";
|
|||
import { SPACING_UNIT } from "../../theme.css";
|
||||
import { format } from "date-fns";
|
||||
import { SelectFolderModal } from "./select-folder-modal";
|
||||
import { SeedersAndPeers } from "./seeders-and-peers/seeders-and-peers";
|
||||
import {
|
||||
isMultiplayerRepack,
|
||||
supportMultiLanguage,
|
||||
} from "@renderer/helpers/searcher";
|
||||
import { Tag } from "@renderer/components/tag/tag";
|
||||
import { getRepackLanguageBasedOnRepacker } from "../../helpers/searcher";
|
||||
import { useAppSelector } from "@renderer/hooks";
|
||||
|
||||
export interface RepacksModalProps {
|
||||
visible: boolean;
|
||||
|
@ -34,9 +26,6 @@ export function RepacksModal({
|
|||
const [filteredRepacks, setFilteredRepacks] = useState<GameRepack[]>([]);
|
||||
const [repack, setRepack] = useState<GameRepack | null>(null);
|
||||
const [showSelectFolderModal, setShowSelectFolderModal] = useState(false);
|
||||
const { value: userPreferences } = useAppSelector(
|
||||
(state) => state.userPreferences
|
||||
);
|
||||
|
||||
const { t } = useTranslation("game_details");
|
||||
|
||||
|
@ -94,41 +83,12 @@ export function RepacksModal({
|
|||
<p style={{ color: "#DADBE1", wordBreak: "break-word" }}>
|
||||
{repack.title}
|
||||
</p>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<p style={{ fontSize: "12px" }}>
|
||||
{repack.fileSize} - {repack.repacker} -{" "}
|
||||
{repack.uploadDate
|
||||
? format(repack.uploadDate, "dd/MM/yyyy")
|
||||
: ""}
|
||||
{userPreferences?.language && (
|
||||
<>
|
||||
{" - " +
|
||||
getRepackLanguageBasedOnRepacker(
|
||||
repack.repacker,
|
||||
userPreferences?.language
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<SeedersAndPeers repack={repack} />
|
||||
</div>
|
||||
<div className={styles.tagsContainer}>
|
||||
{supportMultiLanguage(repack.title) && (
|
||||
<Tag>{t("multi_language")}</Tag>
|
||||
)}
|
||||
{isMultiplayerRepack(repack.title, repack.repacker) && (
|
||||
<Tag>{t("multiplayer")}</Tag>
|
||||
)}
|
||||
</div>
|
||||
<p style={{ fontSize: "12px" }}>
|
||||
{repack.fileSize} - {repack.repacker} -{" "}
|
||||
{repack.uploadDate
|
||||
? format(repack.uploadDate, "dd/MM/yyyy")
|
||||
: ""}
|
||||
</p>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
import Skeleton from "react-loading-skeleton";
|
||||
|
||||
export function SeedersAndPeersSkeleton() {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
}}
|
||||
>
|
||||
<Skeleton width={40} height={20} />
|
||||
<Skeleton
|
||||
width={40}
|
||||
height={20}
|
||||
style={{
|
||||
marginLeft: "12px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
import { GameRepack } from "@types";
|
||||
import UsersIcon from "@renderer/assets/users-icon.svg?react";
|
||||
import SproutIcon from "@renderer/assets/sprout-icon.svg?react";
|
||||
|
||||
import { useMagnetHealth } from "./useMagnetHealth";
|
||||
import { Tooltip } from "@renderer/components/tooltip/tooltip";
|
||||
import { SeedersAndPeersSkeleton } from "./seeders-and-peers-skeleton";
|
||||
import { SPACING_UNIT, vars } from "@renderer/theme.css";
|
||||
|
||||
interface SeedersAndPeersProps {
|
||||
repack: GameRepack;
|
||||
}
|
||||
|
||||
export function SeedersAndPeers({ repack }: Readonly<SeedersAndPeersProps>) {
|
||||
const { magnetData, isLoading, error } = useMagnetHealth(repack.magnet);
|
||||
|
||||
if (isLoading) {
|
||||
return <SeedersAndPeersSkeleton />;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-around",
|
||||
}}
|
||||
>
|
||||
<Tooltip tooltipText="Seeders">
|
||||
<SproutIcon stroke={vars.color.bodyText} />
|
||||
<span
|
||||
style={{
|
||||
marginLeft: `${SPACING_UNIT - 5}px`,
|
||||
marginRight: `${SPACING_UNIT}px`,
|
||||
}}
|
||||
>
|
||||
{magnetData?.seeders}
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Tooltip tooltipText="Peers">
|
||||
<UsersIcon stroke={vars.color.bodyText} />
|
||||
<span
|
||||
style={{
|
||||
marginLeft: `${SPACING_UNIT - 5}px`,
|
||||
}}
|
||||
>
|
||||
{magnetData?.peers}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
export type TorrentData = {
|
||||
seeders: number;
|
||||
peers: number;
|
||||
lastTracked?: Date;
|
||||
};
|
|
@ -1,80 +0,0 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { TorrentData } from "./types";
|
||||
|
||||
const cache: Record<string, TorrentData> = {};
|
||||
|
||||
export function useMagnetHealth(magnet: string) {
|
||||
const [magnetData, setMagnetData] = useState<TorrentData | null>(
|
||||
cache[magnet] || null
|
||||
);
|
||||
const [isLoading, setIsLoading] = useState(() => {
|
||||
if (cache[magnet]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!magnet) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cache[magnet]) {
|
||||
setMagnetData(cache[magnet]);
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
window.electron
|
||||
.getMagnetHealth(magnet)
|
||||
.then(
|
||||
(result) => {
|
||||
if (result) {
|
||||
setMagnetData(result);
|
||||
setIsLoading(false);
|
||||
|
||||
cache[magnet] = result;
|
||||
cache[magnet].lastTracked = new Date();
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
setError(error);
|
||||
setIsLoading(false);
|
||||
}
|
||||
)
|
||||
.catch(() => {});
|
||||
}, [magnet]);
|
||||
|
||||
useEffect(() => {
|
||||
function invalidateCache() {
|
||||
const TWO_MINUTES = 2 * 60 * 1000;
|
||||
const cacheExpiresIn = TWO_MINUTES;
|
||||
|
||||
Object.keys(cache).forEach((key) => {
|
||||
const lastTracked = cache[key].lastTracked;
|
||||
|
||||
if (!lastTracked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Date.now() - lastTracked.getTime() > cacheExpiresIn) {
|
||||
delete cache[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
invalidateCache();
|
||||
|
||||
return () => {
|
||||
invalidateCache();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return {
|
||||
magnetData,
|
||||
isLoading,
|
||||
error,
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue