Skip to content

Commit

Permalink
[feat-684] add icons for mods version comparison
Browse files Browse the repository at this point in the history
  • Loading branch information
silentrald committed Dec 29, 2024
1 parent 5d480db commit 17b92ee
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { useEffect, useState } from "react";
import { logRenderError } from "renderer";
import { BsmSelect, BsmSelectOption } from "renderer/components/shared/bsm-select.component";
import { AddIcon } from "renderer/components/svgs/icons/add-icon.component";
import { DownIcon } from "renderer/components/svgs/icons/down-icon.component";
import { EqualIcon } from "renderer/components/svgs/icons/equals-icon.component";
import { RemoveIcon } from "renderer/components/svgs/icons/remove-icon.component";
import { UpIcon } from "renderer/components/svgs/icons/up-icon.component";
import { useConstant } from "renderer/hooks/use-constant.hook";
import { useService } from "renderer/hooks/use-service.hook";
import { useTranslationV2 } from "renderer/hooks/use-translation.hook";
Expand Down Expand Up @@ -131,10 +136,11 @@ function useHeader({
}

// Manual in-memory caching
modsMapCache.set(otherVersion, {
const newCache = new Map(modsMapCache);
newCache.set(otherVersion, {
availableModsMap, installedModsMap,
});
setModsMapCache(modsMapCache);
setModsMapCache(newCache);

setOtherAvailableModsMap(availableModsMap);
setOtherInstalledModsMap(installedModsMap);
Expand All @@ -144,7 +150,8 @@ function useHeader({


return {
mode, otherAvailableModsMap, otherInstalledModsMap,
mode,
otherVersion, otherAvailableModsMap, otherInstalledModsMap,

renderHeader: () => <div className="grid grid-cols-2 text-large mb-2">
<div className="flex justify-center gap-x-2">
Expand All @@ -165,7 +172,6 @@ function useHeader({
onChange={setOtherVersion}
/>
</div>

};
}

Expand All @@ -174,65 +180,101 @@ function ModCompare({
installed,
otherMod,
otherInstalled,
otherInstalledLocal,
loading,
}: Readonly<{
mod: Mod | null;
installed: boolean;
otherMod: Mod | null;
otherInstalled: boolean;
// Check if the other version is installed locally
otherInstalledLocal: boolean;
loading: boolean;
}>) {
const name = mod?.name || otherMod?.name;

const render = (renderMod: Mod | null, installed_: boolean, loading_: boolean = false) => {
if (loading_) {
const renderMod = () => {
if (!mod) {
return <div className="bg-black py-1 px-2">{name}</div>
}

let modClass = "flex justify-between py-1 px-2 gap-x-2";
if (installed) {
modClass += " bg-green-700";
} else {
modClass += " bg-red-700";
}

return <div className={modClass}>
<div className="text-ellipsis overflow-hidden">{name}</div>
<div>{mod.version}</div>
</div>
}

const renderOtherMod = () => {
if (loading) {
return <div className="bg-black">TODO: Rainbow Lazy Loading</div>
}

if (!renderMod) {
if (!otherMod) {
return <div className="bg-black py-1 px-2">{name}</div>
}

let modClass = "flex justify-between py-1 px-2 gap-x-2";
if (installed_) {
if (!otherInstalledLocal) {
modClass += " bg-blue-700"; // Change, just for visual prototyping
} else if (otherInstalled) {
modClass += " bg-green-700";
} else {
modClass += " bg-red-700";
}

return <div key={renderMod._id} className={modClass}>
return <div className={modClass}>
<div className="text-ellipsis overflow-hidden">{name}</div>
<div>{renderMod.version}</div>
<div>{otherMod.version}</div>
</div>
}

const renderSymbol = () => {
let symbol = "";
const renderIcon = () => {
if (loading) {
return <div />
}

if (mod && !otherMod) {
symbol = "-"; // Removed / Not Submitted Yet
} else if (!mod && otherMod) {
symbol = "+"; // Added
} else if (mod.version === otherMod.version) {
symbol = "="; // Equals
} else if (safeLt(mod.version, otherMod.version)) {
symbol = "^"; // Upgraded
} else {
symbol = "v"; // Downgraded
// Removed / Not Submitted Yet
return <RemoveIcon className="text-center w-6 h-6" />
}

if (!mod && otherMod) {
// Added
return <AddIcon className="text-center w-6 h-6" />
}

if (mod.version === otherMod.version) {
// Equals
return <EqualIcon className="text-center w-6 h-6" />
}

return <div className="text-center font-extrabold">{symbol}</div>
if (safeLt(mod.version, otherMod.version)) {
// Upgraded
return <UpIcon className="text-center w-6 h-6" />
}

// Downgraded
return <DownIcon className="text-center w-6 h-6" />
}

return <>
{render(mod, installed)}
{renderSymbol()}
{render(otherMod, otherInstalled, loading)}
{renderMod()}
{renderIcon()}
{renderOtherMod()}
</>
}

function ModCategory({
mode,
category,
otherVersion,
availableMods,
installedMods,
otherAvailableMods,
Expand All @@ -241,12 +283,15 @@ function ModCategory({
}: Readonly<{
mode: Mode;
category: string;
otherVersion: BSVersion;
availableMods: Mod[];
installedMods: Mod[];
otherAvailableMods: Mod[];
otherInstalledMods: Mod[];
loading: boolean;
}>) {
const otherInstalledLocal = !!otherVersion?.path;

let combinedMods: Mod[] = [];
switch (mode) {
case Mode.All:
Expand All @@ -255,7 +300,7 @@ function ModCategory({
break;
}

availableMods.forEach(mod => {
otherAvailableMods.forEach(mod => {
if (combinedMods.findIndex(cm => cm.name === mod.name) === -1) {
combinedMods.push(mod);
}
Expand Down Expand Up @@ -286,7 +331,7 @@ function ModCategory({
</h2>

<div className="grid" style={{
gridTemplateColumns: "350px 25px 350px"
gridTemplateColumns: "350px 24px 350px"
}}>
{combinedMods.map(mod =>
<ModCompare
Expand All @@ -295,6 +340,7 @@ function ModCategory({
installed={installedMods.findIndex(im => im.name === mod.name) > -1}
otherMod={otherAvailableMods.find(oam => oam.name === mod.name)}
otherInstalled={otherInstalledMods.findIndex(oim => oim.name === mod.name) > -1}
otherInstalledLocal={otherInstalledLocal}
loading={loading}
/>
)}
Expand All @@ -315,7 +361,8 @@ export const ModsVersionCompareModal: ModalComponent<void, Readonly<{

const [loading, setLoading] = useState(false);
const {
mode, otherAvailableModsMap, otherInstalledModsMap,
mode,
otherVersion, otherAvailableModsMap, otherInstalledModsMap,
renderHeader,
} = useHeader({ version, loading, setLoading });

Expand Down Expand Up @@ -343,6 +390,7 @@ export const ModsVersionCompareModal: ModalComponent<void, Readonly<{
key={category}
mode={mode}
category={category}
otherVersion={otherVersion}
availableMods={availableModsMap.get(category) || []}
installedMods={installedModsMap.get(category) || []}
otherAvailableMods={otherAvailableModsMap.get(category) || []}
Expand Down
7 changes: 6 additions & 1 deletion src/renderer/components/svgs/bsm-icon.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,11 @@ import { BrowseIcon } from "./icons/browse-icon.component";
import { AddFileIcon } from "./icons/add-file-icon.component";
import { CancelIcon } from "./icons/cancel-icon.component";
import { WarningIcon } from "./icons/warning-icon.component";
import { CompareIcon } from "./icons/compare-icon.component";



export type BsmIconType = SongDetailDiffCharactertistic | ("settings" | "trash" | "favorite" | "folder" | "bsNote" | "check" | "three-dots" | "twitch" | "eye" | "play" | "checkCircleIcon" | "discord" | "info" | "eye-cross" | "terminal" | "desktop" | "oculus" | "add" | "cross" | "task" | "github" | "close" | "thumbUpFill" | "timerFill" | "pause" | "twitter" | "sync" | "chevron-top" | "copy" | "steam" | "edit" | "export" | "patreon" | "search" | "bsMapDifficulty" | "link" | "unlink" | "download" | "filter" | "mee6" | "volume-up" | "volume-off" | "volume-down" | "shortcut" | "backup-restore" | "web-site" | "clean" | "browse" | "add-file" | "cancel" | "warning" | "fr-FR-flag" | "es-ES-flag" | "en-US-flag" | "en-EN-flag" | "de-DE-flag" | "ru-RU-flag" | "zh-CN-flag" | "zh-TW-flag" | "ja-JP-flag" | "ko-KR-flag" | "null" );
export type BsmIconType = SongDetailDiffCharactertistic | ("settings" | "trash" | "favorite" | "folder" | "bsNote" | "check" | "three-dots" | "twitch" | "eye" | "play" | "checkCircleIcon" | "discord" | "info" | "eye-cross" | "terminal" | "desktop" | "oculus" | "add" | "cross" | "task" | "github" | "close" | "thumbUpFill" | "timerFill" | "pause" | "twitter" | "sync" | "chevron-top" | "copy" | "steam" | "edit" | "export" | "patreon" | "search" | "bsMapDifficulty" | "link" | "unlink" | "download" | "filter" | "mee6" | "volume-up" | "volume-off" | "volume-down" | "shortcut" | "backup-restore" | "web-site" | "clean" | "browse" | "add-file" | "cancel" | "warning" | "compare" | "fr-FR-flag" | "es-ES-flag" | "en-US-flag" | "en-EN-flag" | "de-DE-flag" | "ru-RU-flag" | "zh-CN-flag" | "zh-TW-flag" | "ja-JP-flag" | "ko-KR-flag" | "null" );

export const BsmIcon = memo(({ className, icon, style }: { className?: string; icon: BsmIconType; style?: CSSProperties }) => {
// TODO : Very ugly very messy, need to find a better way to do this
Expand Down Expand Up @@ -288,6 +289,10 @@ export const BsmIcon = memo(({ className, icon, style }: { className?: string; i
return <WarningIcon className={className} style={style} />
}

if (icon === "compare") {
return <CompareIcon className={className} style={style} />
}

return <TrashIcon className={className} style={style} />;


Expand Down
15 changes: 15 additions & 0 deletions src/renderer/components/svgs/icons/compare-icon.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { CSSProperties } from "react";

export function CompareIcon(props: { className?: string; style?: CSSProperties }) {
return (
<svg
className={props.className}
style={props.style}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
fill="currentColor"
>
<path d="M367-320H120q-17 0-28.5-11.5T80-360q0-17 11.5-28.5T120-400h247l-75-75q-11-11-11-27.5t11-28.5q12-12 28.5-12t28.5 12l143 143q6 6 8.5 13t2.5 15q0 8-2.5 15t-8.5 13L348-188q-12 12-28 11.5T292-189q-11-12-11.5-28t11.5-28l75-75Zm226-240 75 75q11 11 11 27.5T668-429q-12 12-28.5 12T611-429L468-572q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l144-144q12-12 28-11.5t28 12.5q11 12 11.5 28T668-715l-75 75h247q17 0 28.5 11.5T880-600q0 17-11.5 28.5T840-560H593Z" />
</svg>
);
}
15 changes: 15 additions & 0 deletions src/renderer/components/svgs/icons/down-icon.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { CSSProperties } from "react";

export function DownIcon(props: { className?: string; style?: CSSProperties }) {
return (
<svg
className={props.className}
style={props.style}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
fill="currentColor"
>
<path d="M440-313v-447q0-17 11.5-28.5T480-800q17 0 28.5 11.5T520-760v447l196-196q12-12 28-11.5t28 12.5q11 12 11.5 28T772-452L508-188q-6 6-13 8.5t-15 2.5q-8 0-15-2.5t-13-8.5L188-452q-11-11-11-27.5t11-28.5q12-12 28.5-12t28.5 12l195 195Z" />
</svg>
);
}
15 changes: 15 additions & 0 deletions src/renderer/components/svgs/icons/equals-icon.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { CSSProperties } from "react";

export function EqualIcon(props: { className?: string; style?: CSSProperties }) {
return (
<svg
className={props.className}
style={props.style}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
fill="currentColor"
>
<path d="M220-280q-25 0-42.5-17.5T160-340q0-25 17.5-42.5T220-400h520q25 0 42.5 17.5T800-340q0 25-17.5 42.5T740-280H220Zm0-280q-25 0-42.5-17.5T160-620q0-25 17.5-42.5T220-680h520q25 0 42.5 17.5T800-620q0 25-17.5 42.5T740-560H220Z" />
</svg>
);
}
15 changes: 15 additions & 0 deletions src/renderer/components/svgs/icons/remove-icon.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { CSSProperties } from "react";

export function RemoveIcon(props: { className?: string; style?: CSSProperties }) {
return (
<svg
className={props.className}
style={props.style}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
fill="currentColor"
>
<path d="M240-440q-17 0-28.5-11.5T200-480q0-17 11.5-28.5T240-520h480q17 0 28.5 11.5T760-480q0 17-11.5 28.5T720-440H240Z" />
</svg>
)
}
15 changes: 15 additions & 0 deletions src/renderer/components/svgs/icons/up-icon.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { CSSProperties } from "react";

export function UpIcon(props: { className?: string; style?: CSSProperties }) {
return (
<svg
className={props.className}
style={props.style}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
fill="currentColor"
>
<path d="M440-647 244-451q-12 12-28 11.5T188-452q-11-12-11.5-28t11.5-28l264-264q6-6 13-8.5t15-2.5q8 0 15 2.5t13 8.5l264 264q11 11 11 27.5T772-452q-12 12-28.5 12T715-452L520-647v447q0 17-11.5 28.5T480-160q-17 0-28.5-11.5T440-200v-447Z" />
</svg>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export function ModsGrid({ modsMap, installed, modsSelected, onModChange, moreIn
<span className="z-10 sticky top-0 bg-inherit border-b-2 border-main-color-1 h-8 flex justify-start items-center py-1 pl-[3px] min-w-[50px]">
<BsmDropdownButton className="h-full aspect-square relative rounded-full bg-light-main-color-1 dark:bg-main-color-3" withBar={false} icon="three-dots" buttonClassName="!rounded-full !p-[2px] !bg-light-main-color-2 dark:!bg-main-color-2 hover:!bg-light-main-color-1 dark:hover:!bg-main-color-3" menuTranslationY="5px" items={[
{ text: "pages.version-viewer.mods.mods-grid.header-bar.dropdown.import-mods", icon: "download", onClick: () => openModsDropZone?.() },
{ text: "pages.version-viewer.mods.mods-grid.header-bar.dropdown.compare-mods", icon: "null", onClick: () => openModsVersionCompare?.() },
{ text: "pages.version-viewer.mods.mods-grid.header-bar.dropdown.compare-mods", icon: "compare", onClick: () => openModsVersionCompare?.() },
{ text: "pages.version-viewer.mods.mods-grid.header-bar.dropdown.unselect-all", icon: "cancel", onClick: () => unselectAllMods?.() },
{ text: "pages.version-viewer.mods.mods-grid.header-bar.dropdown.uninstall-all", icon: "trash", onClick: () => uninstallAllMods?.() }
]} />
Expand Down

0 comments on commit 17b92ee

Please sign in to comment.