Paper and Purpur + Backups (#3004)

* feat: init selecting paper+purpur on purchase flow

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat: properly implement Paper/Purpur in Platform

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: correct wording

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat: redo platform modal

Signed-off-by: Evan Song <theevansong@gmail.com>

* Switch to HCaptcha for Auth-related captchas (#2945)

* Switch to HCaptcha for Auth-related captchas

* run fmt

* fix hcaptcha not loading

* fix: more robust loader dropdown logic

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: handle "not yet supported" install err

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: fix icon kerfuffles

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: improve vanilla install modal title

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: spacing

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: improve no loader state

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: type error

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: adjust mod version modal title

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: adjust modpack warning copy

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat: vanilla empty state in content page

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: adjust copy

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: update icon

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: loader type

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: loader type

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat: always show dropdown if possible

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: improve spacing

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: appear disabled

Signed-off-by: Evan Song <theevansong@gmail.com>

* h

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: if reinstalling, show it on the modal title

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat: put it in the dropdown, they said

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: adjust style

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: sort paper-purpur versions desc

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: do not consider backup limit in reinstall prompt

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat: backup locking, plugin support

* fix: content type error

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: casing

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: plugins pt 2

* feat: backups, mrpack

* fix: type errors come on

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: spacing

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: type maxing

* chore: show copy button on allocation rows

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat: suspend improvement

---------

Signed-off-by: Evan Song <theevansong@gmail.com>
Co-authored-by: Evan Song <theevansong@gmail.com>
Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
Co-authored-by: Jai A <jaiagr+gpg@pm.me>
Co-authored-by: Evan Song <52982404+ferothefox@users.noreply.github.com>
This commit is contained in:
TheWander02
2024-12-10 23:49:50 -07:00
committed by GitHub
parent eff3189ded
commit 742c0edd9e
26 changed files with 952 additions and 248 deletions

View File

@@ -44,7 +44,7 @@ import { ButtonStyled, NewModal } from "@modrinth/ui";
import { PlusIcon, XIcon, InfoIcon } from "@modrinth/assets";
const props = defineProps<{
server: Server<["general", "mods", "backups", "network", "startup", "ws", "fs"]>;
server: Server<["general", "content", "backups", "network", "startup", "ws", "fs"]>;
}>();
const emit = defineEmits(["backupCreated"]);

View File

@@ -104,7 +104,7 @@ const modal = ref<InstanceType<typeof NewModal>>();
const initialSettings = ref<{ interval: number; enabled: boolean } | null>(null);
const autoBackupEnabled = ref(false);
const autoBackupInterval = ref(1);
const autoBackupInterval = ref(6);
const isLoadingSettings = ref(true);
const isSaving = ref(false);
@@ -134,7 +134,7 @@ const fetchSettings = async () => {
const settings = await props.server.backups?.getAutoBackup();
initialSettings.value = settings as { interval: number; enabled: boolean };
autoBackupEnabled.value = settings?.enabled ?? false;
autoBackupInterval.value = settings?.interval || 1;
autoBackupInterval.value = settings?.interval || 6;
} catch (error) {
console.error("Error fetching backup settings:", error);
addNotification({

View File

@@ -1,52 +1,60 @@
<template>
<div
v-for="loader in loaders"
:key="loader.name"
class="group relative flex items-center justify-between rounded-2xl p-2 pr-2.5 hover:bg-bg"
>
<div class="flex items-center gap-4">
<div class="flex w-full flex-col gap-1 rounded-2xl bg-table-alternateRow p-2">
<div
v-for="loader in vanillaLoaders"
:key="loader.name"
class="group relative flex items-center justify-between rounded-2xl p-2 pr-2.5 hover:bg-bg"
>
<UiServersLoaderSelectorCard
:loader="loader"
:is-current="isCurrentLoader(loader.name)"
:loader-version="data.loader_version"
:current-loader="data.loader"
@select="selectLoader"
/>
</div>
</div>
<div class="mt-4">
<h2 class="mb-2 px-2 text-lg font-bold text-contrast">Mod loaders</h2>
<div class="flex w-full flex-col gap-1 rounded-2xl bg-table-alternateRow p-2">
<div
class="grid size-10 place-content-center rounded-xl border-[1px] border-solid border-button-border bg-button-bg shadow-sm"
:class="isCurrentLoader(loader.name) ? '[&&]:bg-bg-green' : ''"
v-for="loader in modLoaders"
:key="loader.name"
class="group relative flex items-center justify-between rounded-2xl p-2 pr-2.5 hover:bg-bg"
>
<UiServersIconsLoaderIcon
:loader="loader.name"
class="[&&]:size-6"
:class="isCurrentLoader(loader.name) ? 'text-brand' : ''"
<UiServersLoaderSelectorCard
:loader="loader"
:is-current="isCurrentLoader(loader.name)"
:loader-version="data.loader_version"
:current-loader="data.loader"
@select="selectLoader"
/>
</div>
<div class="flex flex-col gap-0.5">
<div class="flex flex-row items-center gap-2">
<h1 class="m-0 text-xl font-bold leading-none text-contrast">
{{ loader.displayName }}
</h1>
<span
v-if="isCurrentLoader(loader.name)"
class="hidden items-center gap-1 rounded-full bg-bg-green p-1 px-1.5 text-xs font-semibold text-brand sm:flex"
>
<CheckIcon class="h-4 w-4" />
Current
</span>
</div>
<p v-if="isCurrentLoader(loader.name)" class="m-0 text-xs text-secondary">
{{ data.loader_version }}
</p>
</div>
</div>
<div class="mt-4">
<h2 class="mb-2 px-2 text-lg font-bold text-contrast">Plugin loaders</h2>
<div class="flex w-full flex-col gap-1 rounded-2xl bg-table-alternateRow p-2">
<div
v-for="loader in pluginLoaders"
:key="loader.name"
class="group relative flex items-center justify-between rounded-2xl p-2 pr-2.5 hover:bg-bg"
>
<UiServersLoaderSelectorCard
:loader="loader"
:is-current="isCurrentLoader(loader.name)"
:loader-version="data.loader_version"
:current-loader="data.loader"
@select="selectLoader"
/>
</div>
</div>
<ButtonStyled>
<button @click="selectLoader(loader.name)">
<DownloadIcon class="h-5 w-5" />
{{ isCurrentLoader(loader.name) ? "Reinstall" : "Install" }}
</button>
</ButtonStyled>
</div>
</template>
<script setup lang="ts">
import { CheckIcon, DownloadIcon } from "@modrinth/assets";
import { ButtonStyled } from "@modrinth/ui";
const props = defineProps<{
data: {
loader: string | null;
@@ -58,14 +66,20 @@ const emit = defineEmits<{
(e: "selectLoader", loader: string): void;
}>();
const loaders = [
{ name: "Vanilla" as const, displayName: "Vanilla" },
const vanillaLoaders = [{ name: "Vanilla" as const, displayName: "Vanilla" }];
const modLoaders = [
{ name: "Fabric" as const, displayName: "Fabric" },
{ name: "Quilt" as const, displayName: "Quilt" },
{ name: "Forge" as const, displayName: "Forge" },
{ name: "NeoForge" as const, displayName: "NeoForge" },
];
const pluginLoaders = [
{ name: "Paper" as const, displayName: "Paper" },
{ name: "Purpur" as const, displayName: "Purpur" },
];
const isCurrentLoader = (loaderName: string) => {
return props.data.loader?.toLowerCase() === loaderName.toLowerCase();
};

View File

@@ -0,0 +1,70 @@
<template>
<div class="flex w-full items-center justify-between">
<div class="flex items-center gap-4">
<div
class="grid size-10 place-content-center rounded-xl border-[1px] border-solid border-button-border bg-button-bg shadow-sm"
:class="isCurrentLoader ? '[&&]:bg-bg-green' : ''"
>
<UiServersIconsLoaderIcon
:loader="loader.name"
class="[&&]:size-6"
:class="isCurrentLoader ? 'text-brand' : ''"
/>
</div>
<div class="flex flex-col gap-0.5">
<div class="flex flex-row items-center gap-2">
<h1 class="m-0 text-xl font-bold leading-none text-contrast">
{{ loader.displayName }}
</h1>
<span
v-if="isCurrentLoader"
class="hidden items-center gap-1 rounded-full bg-bg-green p-1 px-1.5 text-xs font-semibold text-brand sm:flex"
>
<CheckIcon class="h-4 w-4" />
Current
</span>
</div>
<p v-if="isCurrentLoader" class="m-0 text-xs text-secondary">
{{ loaderVersion }}
</p>
</div>
</div>
<ButtonStyled>
<button @click="onSelect">
<DownloadIcon class="h-5 w-5" />
{{ isCurrentLoader ? "Reinstall" : "Install" }}
</button>
</ButtonStyled>
</div>
</template>
<script setup lang="ts">
import { CheckIcon, DownloadIcon } from "@modrinth/assets";
import { ButtonStyled } from "@modrinth/ui";
interface LoaderInfo {
name: "Vanilla" | "Fabric" | "Forge" | "Quilt" | "Paper" | "NeoForge" | "Purpur";
displayName: string;
}
interface Props {
loader: LoaderInfo;
currentLoader: string | null;
loaderVersion: string | null;
}
const props = defineProps<Props>();
const emit = defineEmits<{
(e: "select", loader: string): void;
}>();
const isCurrentLoader = computed(() => {
return props.currentLoader?.toLowerCase() === props.loader.name.toLowerCase();
});
const onSelect = () => {
emit("select", props.loader.name);
};
</script>

View File

@@ -1,11 +1,26 @@
<template>
<NuxtLink class="contents" :to="`/servers/manage/${props.server_id}`">
<NuxtLink
class="contents"
:to="status === 'suspended' ? '' : `/servers/manage/${props.server_id}`"
>
<div
class="flex cursor-pointer flex-row items-center overflow-x-hidden rounded-3xl bg-bg-raised p-4 transition-transform duration-100 active:scale-95"
v-tooltip="
status === 'suspended'
? `This server is suspended visit the billing page to learn more`
: ''
"
class="flex cursor-pointer flex-row items-center overflow-x-hidden rounded-3xl bg-bg-raised p-4 transition-transform duration-100"
:class="status === 'suspended' ? 'opacity-50' : 'active:scale-95'"
data-pyro-server-listing
:data-pyro-server-listing-id="server_id"
>
<UiServersServerIcon :image="image" />
<UiServersServerIcon v-if="status !== 'suspended'" :image="image" />
<div
v-else
class="bg-bg-secondary flex size-24 items-center justify-center rounded-xl border-[1px] border-solid border-button-border bg-button-bg shadow-sm"
>
<LockIcon class="size-20 text-secondary" />
</div>
<div class="ml-8 flex flex-col gap-2.5">
<div class="flex flex-row items-center gap-2">
<h2 class="m-0 text-xl font-bold text-contrast">{{ name }}</h2>
@@ -40,7 +55,7 @@
</template>
<script setup lang="ts">
import { ChevronRightIcon } from "@modrinth/assets";
import { ChevronRightIcon, LockIcon } from "@modrinth/assets";
import type { Project, Server } from "~/types/servers";
const props = defineProps<Partial<Server>>();

View File

@@ -153,6 +153,65 @@
/>
</g>
</svg>
<svg
v-else-if="loader === 'Purpur'"
xml:space="preserve"
fill-rule="evenodd"
stroke-linecap="round"
stroke-linejoin="round"
stroke-miterlimit="1.5"
clip-rule="evenodd"
viewBox="0 0 24 24"
>
<defs>
<path
id="purpur"
fill="none"
stroke="currentColor"
stroke-width="1.68"
d="m264 41.95 8-4v8l-8 4v-8Z"
></path>
</defs>
<path fill="none" d="M0 0h24v24H0z"></path>
<path
fill="none"
stroke="currentColor"
stroke-width="1.77"
d="m264 29.95-8 4 8 4.42 8-4.42-8-4Z"
transform="matrix(1.125 0 0 1.1372 -285 -31.69)"
></path>
<path
fill="none"
stroke="currentColor"
stroke-width="1.77"
d="m272 38.37-8 4.42-8-4.42"
transform="matrix(1.125 0 0 1.1372 -285 -31.69)"
></path>
<path
fill="none"
stroke="currentColor"
stroke-width="1.77"
d="m260 31.95 8 4.21V45"
transform="matrix(1.125 0 0 1.1372 -285 -31.69)"
></path>
<path
fill="none"
stroke="currentColor"
stroke-width="1.77"
d="M260 45v-8.84l8-4.21"
transform="matrix(1.125 0 0 1.1372 -285 -31.69)"
></path>
<use
xlink:href="#purpur"
stroke-width="1.68"
transform="matrix(1.125 0 0 1.2569 -285 -40.78)"
></use>
<use
xlink:href="#purpur"
stroke-width="1.68"
transform="matrix(-1.125 0 0 1.2569 309 -40.78)"
></use>
</svg>
<svg v-else-if="loader === 'Vanilla'" viewBox="0 0 20 20" fill="currentColor">
<path
fill-rule="evenodd"
@@ -165,8 +224,9 @@
<script setup lang="ts">
import { LoaderIcon } from "@modrinth/assets";
import type { Loaders } from "~/types/servers";
defineProps<{
loader: "Fabric" | "Quilt" | "Forge" | "NeoForge" | "Paper" | "Spigot" | "Bukkit" | "Vanilla";
loader: Loaders;
}>();
</script>