Skip to content

Commit

Permalink
feat: use enhanced select for CurseForge strategy
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Cao <[email protected]>
  • Loading branch information
ryanccn committed Nov 10, 2023
1 parent c61c2de commit 15f3fbb
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 77 deletions.
40 changes: 40 additions & 0 deletions src/components/ui/Select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { twMerge } from "tailwind-merge";
import { type ReactNode } from "react";

export const Select = <T extends string>({
name,
value,
currentValue,
onCheck,
children,
className,
}: {
name: string;
value: T;
currentValue: T;
onCheck?: (v: T) => void | Promise<void>;
className?: string;
children?: ReactNode | ReactNode[];
}) => {
return (
<label
className={twMerge(
"flex w-full flex-col items-start gap-y-2 rounded-md p-4 hover:cursor-pointer",
value === currentValue ? "bg-indigo-500 text-white" : "bg-neutral-100 dark:bg-neutral-800",
className,
)}
>
<input
type="radio"
className="sr-only"
name={name}
value={value}
checked={value === currentValue}
onChange={(ev) => {
if (onCheck && ev.target.value) onCheck(ev.target.value as T);
}}
/>
{children}
</label>
);
};
14 changes: 10 additions & 4 deletions src/lib/export/formats/mrpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,16 @@ const sha512 = async (f: ArrayBuffer) => {
return he;
};

export const enum CurseForgeStrategy {
Embed = "embed",
Links = "links",
Skip = "skip",
}

const generateModrinthPack = async (
list: RichModList,
urls: ExportReturnData,
extraData: { name?: string; version?: string; cfStrategy?: string },
extraData: { name?: string; version?: string; cfStrategy?: CurseForgeStrategy },
) => {
const mrIndex = {
formatVersion: 1,
Expand Down Expand Up @@ -64,7 +70,7 @@ const generateModrinthPack = async (

const mrpack = new JSZip();

if (extraData.cfStrategy === "embed") {
if (extraData.cfStrategy === CurseForgeStrategy.Embed) {
const cfDownloads = urls.filter(
(dl) => !("error" in dl) && dl.provider === "curseforge",
) as CurseForgeDownload[];
Expand All @@ -80,7 +86,7 @@ const generateModrinthPack = async (

mrpack.file(`overrides/mods/${url.name}`, fileContents);
}
} else if (extraData.cfStrategy === "links") {
} else if (extraData.cfStrategy === CurseForgeStrategy.Links) {
const cfDownloads = urls.filter(
(dl) => !("error" in dl) && dl.provider === "curseforge",
) as CurseForgeDownload[];
Expand Down Expand Up @@ -119,7 +125,7 @@ export const modrinthExport = async ({
setStatus,
}: {
data: RichModList;
mrpackData: { name: string; version: string; cfStrategy: string };
mrpackData: { name: string; version: string; cfStrategy: CurseForgeStrategy };
} & PageStateHooks) => {
setStatus(ExportStatus.Resolving);
setProgress({ value: 0, max: data.mods.length });
Expand Down
76 changes: 49 additions & 27 deletions src/pages/list/[id]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { signIn, useSession } from "next-auth/react";
import { authOptions } from "~/lib/authOptions";
import { getSpecificList } from "~/lib/db";

import { modrinthExport } from "~/lib/export/formats/mrpack";
import { modrinthExport, CurseForgeStrategy as MrpackCurseforgeStrategy } from "~/lib/export/formats/mrpack";
import { prismAutoUpdateExport, prismStaticExport } from "~/lib/export/formats/prism";
import { ExportStatus } from "~/lib/export/formats/shared";
import { zipExport } from "~/lib/export/formats/zip";
Expand All @@ -33,8 +33,10 @@ import { DonationMessage } from "~/components/partials/DonationMessage";
import { RichModDisplay } from "~/components/partials/RichModDisplay";
import { Search } from "~/components/partials/Search";
import { Spinner } from "~/components/partials/Spinner";
import { Metadata } from "~/components/partials/Metadata";
import { ProgressOverlay } from "~/components/ProgressOverlay";
import { Button, buttonVariants } from "~/components/ui/Button";
import { Select } from "~/components/ui/Select";

import {
AreaChartIcon,
Expand All @@ -57,7 +59,6 @@ import { MarkdownIcon, ModrinthIcon } from "~/components/icons";

import toast from "react-hot-toast";
import { twMerge } from "tailwind-merge";
import { Metadata } from "~/components/partials/Metadata";

interface PageProps {
data: ModListWithExtraData;
Expand Down Expand Up @@ -96,7 +97,9 @@ const ListPage: NextPage<PageProps> = ({ data }) => {

const [mrpackName, setMrpackName] = useState(data.title);
const [mrpackVersion, setMrpackVersion] = useState("0.0.1");
const [mrpackCurseForgeStrategy, setMrpackCurseForgeStrategy] = useState("skip");
const [mrpackCurseForgeStrategy, setMrpackCurseForgeStrategy] = useState<MrpackCurseforgeStrategy>(
MrpackCurseforgeStrategy.Skip,
);

const [progress, setProgress] = useState({ value: 0, max: 0 });
const [result, setResult] = useState<{ success: string[]; failed: string[] }>({
Expand Down Expand Up @@ -711,7 +714,7 @@ ${
}}
>
<label className="flex flex-col gap-y-1">
<span className="font-display text-sm font-medium">Name</span>
<span className="font-display text-sm font-semibold">Name</span>
<input
className="mm-input"
required
Expand All @@ -722,8 +725,9 @@ ${
}}
/>
</label>

<label className="flex flex-col gap-y-1">
<span className="font-display text-sm font-medium">Version</span>
<span className="font-display text-sm font-semibold">Version</span>

<input
className="mm-input"
Expand All @@ -735,30 +739,48 @@ ${
}}
/>
</label>
<label className="flex flex-col gap-y-1">
<span className="font-display text-sm font-medium">CurseForge mods</span>
<select
id="curseforge-strategy"
className="mm-input"
required
value={mrpackCurseForgeStrategy}
onChange={(e) => {
setMrpackCurseForgeStrategy(e.target.value);
}}
>
<option value="embed">Embed files</option>
<option value="links">Include download links</option>
<option value="skip">Skip</option>
</select>
</label>

{mrpackCurseForgeStrategy !== "skip" && (
<div className="rounded bg-yellow-100 p-4 font-semibold text-yellow-900 dark:bg-yellow-900 dark:text-yellow-100">
{mrpackCurseForgeStrategy === "embed"
? "Make sure you have the rights to embed these files in your modpack distribution!"
: "This modpack will be ineligible for publication on Modrinth."}
<label className="flex flex-col gap-y-2">
<span className="font-display text-sm font-semibold">CurseForge mods</span>

<div className="flex flex-col gap-1">
<Select
name="curseforge-strategy"
value={MrpackCurseforgeStrategy.Skip}
currentValue={mrpackCurseForgeStrategy}
onCheck={setMrpackCurseForgeStrategy}
>
<span className="font-display text-base font-medium">Skip</span>
<span className="text-xs opacity-60">
CurseForge mods will be skipped and not included in the resulting Modrinth pack.
</span>
</Select>
<Select
name="curseforge-strategy"
value={MrpackCurseforgeStrategy.Links}
currentValue={mrpackCurseForgeStrategy}
onCheck={setMrpackCurseForgeStrategy}
>
<span className="font-display text-base font-medium">Links</span>
<span className="text-xs opacity-60">
CurseForge CDN links will be used in the Modrinth pack. This will make it ineligible for
publishing on Modrinth.
</span>
</Select>
<Select
name="curseforge-strategy"
value={MrpackCurseforgeStrategy.Embed}
currentValue={mrpackCurseForgeStrategy}
onCheck={setMrpackCurseForgeStrategy}
>
<span className="font-display text-base font-medium">Embed</span>
<span className="text-xs opacity-60">
CurseForge mods will be downloaded and embedded into the Modrinth pack. This is
publishable on Modrinth, but make sure you have permission to redistribute the files.
</span>
</Select>
</div>
)}
</label>

<Button variant="modrinth" type="submit" className="self-start">
<ModrinthIcon className="block h-5 w-5" />
Expand Down
54 changes: 8 additions & 46 deletions src/pages/list/[id]/settings.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type GetServerSideProps, type NextPage } from "next";

import { useRouter } from "next/router";
import { ReactNode, useCallback, useEffect, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";

import { getServerSession } from "next-auth";
import { useSession } from "next-auth/react";
Expand All @@ -12,56 +12,18 @@ import Link from "next/link";
import { GlobalLayout } from "~/components/layout/GlobalLayout";
import { Spinner } from "~/components/partials/Spinner";
import { Button } from "~/components/ui/Button";
import { Select } from "~/components/ui/Select";

import { toast } from "react-hot-toast";
import { getSpecificList } from "~/lib/db";
import minecraftVersions from "~/lib/minecraftVersions.json";

import type { ModList, ModLoader } from "~/types/moddermore";
import { twMerge } from "tailwind-merge";

interface PageProps {
data: ModList;
}

const MMRadio = <T extends string>({
name,
value,
currentValue,
onCheck,
children,
className,
}: {
name: string;
value: T;
currentValue: T;
onCheck?: (v: T) => void | Promise<void>;
className?: string;
children?: ReactNode | ReactNode[];
}) => {
return (
<label
className={twMerge(
"flex w-full flex-col items-start gap-y-2 rounded-md p-4 hover:cursor-pointer",
value === currentValue ? "bg-indigo-500 text-white" : "bg-neutral-100 dark:bg-neutral-800",
className,
)}
>
<input
type="radio"
className="sr-only"
name={name}
value={value}
checked={value === currentValue}
onChange={(ev) => {
if (onCheck && ev.target.value) onCheck(ev.target.value as T);
}}
/>
{children}
</label>
);
};

const ListSettings: NextPage<PageProps> = ({ data }) => {
const session = useSession({ required: true });

Expand Down Expand Up @@ -165,16 +127,16 @@ const ListSettings: NextPage<PageProps> = ({ data }) => {
<div className="flex flex-col gap-y-2">
<span className="font-display text-sm font-bold">Visibility</span>
<div className="flex w-full flex-col gap-2 self-stretch md:flex-row">
<MMRadio name="visibility" value={"private"} currentValue={visibility} onCheck={setVisibility}>
<Select name="visibility" value={"private"} currentValue={visibility} onCheck={setVisibility}>
<div className="flex flex-row items-center gap-x-1.5">
<LockIcon className="block h-4 w-4 shrink-0 opacity-75" strokeWidth={2.5} />
<span className="font-display text-lg font-medium">Private</span>
</div>
<span className="text-xs opacity-60">
Only accessible by you. Others visiting the link will see a 404.
</span>
</MMRadio>
<MMRadio name="visibility" value={"unlisted"} currentValue={visibility} onCheck={setVisibility}>
</Select>
<Select name="visibility" value={"unlisted"} currentValue={visibility} onCheck={setVisibility}>
<div className="flex flex-row items-center gap-x-1.5">
<ShieldIcon className="block h-4 w-4 shrink-0 opacity-75" strokeWidth={2.5} />
<span className="font-display text-lg font-medium">Unlisted</span>
Expand All @@ -183,8 +145,8 @@ const ListSettings: NextPage<PageProps> = ({ data }) => {
Anyone with the link will be able to see the list, and it should not be indexed by search
engines.
</span>
</MMRadio>
<MMRadio name="visibility" value={"public"} currentValue={visibility} onCheck={setVisibility}>
</Select>
<Select name="visibility" value={"public"} currentValue={visibility} onCheck={setVisibility}>
<div className="flex flex-row items-center gap-x-1.5">
<GlobeIcon className="block h-4 w-4 shrink-0 opacity-75" strokeWidth={2.5} />
<span className="font-display text-lg font-medium">Public</span>
Expand All @@ -193,7 +155,7 @@ const ListSettings: NextPage<PageProps> = ({ data }) => {
Anyone with the link will be able to see the list, and it will be available both in Search and
to search engines.
</span>
</MMRadio>
</Select>
</div>
</div>

Expand Down

0 comments on commit 15f3fbb

Please sign in to comment.