Platform page UX improvements (#3009)

* chore: initial fixes from app redesign merge

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

* fix: ccpa hydration error

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

* fix: migrate tailwind to esm

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

* feat: default platform selection to current mc version

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

* fix: navigating and installing content

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

* chore: respect sentence case

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

* fix: match new page padding

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

* feat: allow user to erase all data when installing from modpack

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

* chore: hide hide installed content check if modpack search

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

* chore: wording

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

* chore: make erase data toggle more prominent

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

---------

Signed-off-by: Evan Song <theevansong@gmail.com>
This commit is contained in:
Evan Song 2024-12-12 16:12:54 -07:00 committed by GitHub
parent 1f060b8513
commit e86c9df39d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 159 additions and 118 deletions

View File

@ -21,6 +21,7 @@
within the last twelve (12) months: within the last twelve (12) months:
</p> </p>
<table> <table>
<tbody>
<tr> <tr>
<th>Category</th> <th>Category</th>
<th>Examples</th> <th>Examples</th>
@ -37,15 +38,15 @@
</tr> </tr>
<tr> <tr>
<td> <td>
B. Personal information categories listed in the California Customer Records statute (Cal. B. Personal information categories listed in the California Customer Records statute
Civ. Code § 1798.80(e)). (Cal. Civ. Code § 1798.80(e)).
</td> </td>
<td> <td>
A name, signature, Social Security number, physical characteristics or description, A name, signature, Social Security number, physical characteristics or description,
address, telephone number, passport number, driver's license or state identification card address, telephone number, passport number, driver's license or state identification
number, insurance policy number, education, employment, employment history, bank account card number, insurance policy number, education, employment, employment history, bank
number, credit card number, debit card number, or any other financial information, medical account number, credit card number, debit card number, or any other financial
information, or health insurance information. <br /><br /> information, medical information, or health insurance information. <br /><br />
Some personal information included in this category may overlap with other categories. Some personal information included in this category may overlap with other categories.
</td> </td>
<td>NO</td> <td>NO</td>
@ -53,19 +54,19 @@
<tr> <tr>
<td>C. Protected classification characteristics.</td> <td>C. Protected classification characteristics.</td>
<td> <td>
Age (40 years or older), race, color, ancestry, national origin, citizenship, religion or Age (40 years or older), race, color, ancestry, national origin, citizenship, religion
creed, marital status, medical condition, physical or mental disability, sex (including or creed, marital status, medical condition, physical or mental disability, sex
gender, gender identity, gender expression, pregnancy or childbirth and related medical (including gender, gender identity, gender expression, pregnancy or childbirth and
conditions), sexual orientation, veteran or military status, genetic information related medical conditions), sexual orientation, veteran or military status, genetic
(including familial genetic information). information (including familial genetic information).
</td> </td>
<td>NO</td> <td>NO</td>
</tr> </tr>
<tr> <tr>
<td>D. Commercial information.</td> <td>D. Commercial information.</td>
<td> <td>
Records of personal property, products or services purchased, obtained, or considered, or Records of personal property, products or services purchased, obtained, or considered,
other purchasing or consuming histories or tendencies. or other purchasing or consuming histories or tendencies.
</td> </td>
<td>NO</td> <td>NO</td>
</tr> </tr>
@ -74,16 +75,16 @@
<td> <td>
Genetic, physiological, behavioral, and biological characteristics, or activity patterns Genetic, physiological, behavioral, and biological characteristics, or activity patterns
used to extract a template or other identifier or identifying information, such as, used to extract a template or other identifier or identifying information, such as,
fingerprints, faceprints, and voiceprints, iris or retina scans, keystroke, gait, or other fingerprints, faceprints, and voiceprints, iris or retina scans, keystroke, gait, or
physical patterns, and sleep, health, or exercise data. other physical patterns, and sleep, health, or exercise data.
</td> </td>
<td>NO</td> <td>NO</td>
</tr> </tr>
<tr> <tr>
<td>F. Internet or other similar network activity.</td> <td>F. Internet or other similar network activity.</td>
<td> <td>
Browsing history, search history, information on a consumer's interaction with a website, Browsing history, search history, information on a consumer's interaction with a
application, or advertisement. website, application, or advertisement.
</td> </td>
<td>YES</td> <td>YES</td>
</tr> </tr>
@ -104,8 +105,8 @@
</tr> </tr>
<tr> <tr>
<td> <td>
J. Non-public education information (per the Family Educational Rights and Privacy Act (20 J. Non-public education information (per the Family Educational Rights and Privacy Act
U.S.C. Section 1232g, 34 C.F.R. Part 99)). (20 U.S.C. Section 1232g, 34 C.F.R. Part 99)).
</td> </td>
<td> <td>
Education records directly related to a student maintained by an educational institution Education records directly related to a student maintained by an educational institution
@ -123,6 +124,7 @@
</td> </td>
<td>NO</td> <td>NO</td>
</tr> </tr>
</tbody>
</table> </table>
<p>Personal information does not include:</p> <p>Personal information does not include:</p>
<ul> <ul>

View File

@ -84,7 +84,26 @@
</button> </button>
</ButtonStyled> </ButtonStyled>
</div> </div>
<div v-if="server" class="rounded-2xl bg-bg-raised p-4"> <div v-if="server && projectType.id === 'modpack'" class="rounded-2xl bg-bg-raised">
<div class="flex flex-row items-center gap-2 px-6 py-4 text-contrast">
<h3 class="m-0 text-lg">Options</h3>
</div>
<div class="flex flex-row items-center justify-between gap-2 px-6">
<label for="erase-data-on-install"> Erase all data on install </label>
<input
id="erase-data-on-install"
v-model="eraseDataOnInstall"
label="Erase all data on install"
class="switch stylized-toggle flex-none"
type="checkbox"
/>
</div>
<div class="px-6 py-4 text-sm">
If enabled, existing mods, worlds, and configurations, will be deleted before installing
the selected modpack.
</div>
</div>
<div v-if="server && projectType.id !== 'modpack'" class="rounded-2xl bg-bg-raised p-4">
<Checkbox <Checkbox
v-model="serverHideInstalled" v-model="serverHideInstalled"
label="Hide installed content" label="Hide installed content"
@ -238,7 +257,7 @@
<button <button
v-if=" v-if="
result.installed || result.installed ||
server.mods.data.find((x) => x.project_id === result.project_id) || server.content.data.find((x) => x.project_id === result.project_id) ||
server.general?.project?.id === result.project_id server.general?.project?.id === result.project_id
" "
disabled disabled
@ -328,6 +347,7 @@ const projectTypes = computed(() => [projectType.value.id]);
const server = ref(); const server = ref();
const serverHideInstalled = ref(false); const serverHideInstalled = ref(false);
const eraseDataOnInstall = ref(false);
const PERSISTENT_QUERY_PARAMS = ["sid", "shi"]; const PERSISTENT_QUERY_PARAMS = ["sid", "shi"];
@ -342,7 +362,7 @@ async function updateServerContext() {
if (!auth.value.user) { if (!auth.value.user) {
router.push("/auth/sign-in?redirect=" + encodeURIComponent(route.fullPath)); router.push("/auth/sign-in?redirect=" + encodeURIComponent(route.fullPath));
} else if (route.query.sid !== null) { } else if (route.query.sid !== null) {
server.value = await usePyroServer(route.query.sid, ["general", "mods"]); server.value = await usePyroServer(route.query.sid, ["general", "content"]);
} }
} }
@ -382,7 +402,7 @@ const serverFilters = computed(() => {
} }
if (serverHideInstalled.value) { if (serverHideInstalled.value) {
const installedMods = server.value.mods?.data const installedMods = server.value.content?.data
.filter((x) => x.project_id) .filter((x) => x.project_id)
.map((x) => x.project_id); .map((x) => x.project_id);
@ -461,7 +481,14 @@ async function serverInstall(project) {
) ?? versions[0]; ) ?? versions[0];
if (projectType.value.id === "modpack") { if (projectType.value.id === "modpack") {
await server.value.general?.reinstall(route.query.sid, false, project.project_id, version.id); await server.value.general?.reinstall(
route.query.sid,
false,
project.project_id,
version.id,
undefined,
eraseDataOnInstall.value,
);
project.installed = true; project.installed = true;
navigateTo(`/servers/manage/${route.query.sid}/options/loader`); navigateTo(`/servers/manage/${route.query.sid}/options/loader`);
} else if (projectType.value.id === "mod") { } else if (projectType.value.id === "mod") {
@ -817,4 +844,8 @@ useSeoMeta({
mask-image: linear-gradient(to bottom, black, transparent); mask-image: linear-gradient(to bottom, black, transparent);
opacity: 0.25; opacity: 0.25;
} }
.stylized-toggle:checked::after {
background: var(--color-accent-contrast) !important;
}
</style> </style>

View File

@ -86,10 +86,12 @@
</ButtonStyled> </ButtonStyled>
</div> </div>
</div> </div>
<!-- SERVER START -->
<div <div
v-else-if="serverData" v-else-if="serverData"
data-pyro-server-manager-root data-pyro-server-manager-root
class="experimental-styles-within mobile-blurred-servericon relative mx-auto box-border flex min-h-screen w-full min-w-0 max-w-[1280px] flex-col gap-6 px-3 transition-all duration-300" class="experimental-styles-within mobile-blurred-servericon relative mx-auto box-border flex min-h-screen w-full min-w-0 max-w-[1280px] flex-col gap-6 px-6 transition-all duration-300"
:style="{ :style="{
'--server-bg-image': serverData.image '--server-bg-image': serverData.image
? `url(${serverData.image})` ? `url(${serverData.image})`
@ -302,6 +304,7 @@ import {
import DOMPurify from "dompurify"; import DOMPurify from "dompurify";
import { ButtonStyled } from "@modrinth/ui"; import { ButtonStyled } from "@modrinth/ui";
import { Intercom, shutdown } from "@intercom/messenger-js-sdk"; import { Intercom, shutdown } from "@intercom/messenger-js-sdk";
import { reloadNuxtApp } from "#app";
import type { ServerState, Stats, WSEvent, WSInstallationResultEvent } from "~/types/servers"; import type { ServerState, Stats, WSEvent, WSInstallationResultEvent } from "~/types/servers";
import { usePyroConsole } from "~/store/console.ts"; import { usePyroConsole } from "~/store/console.ts";

View File

@ -237,7 +237,7 @@ import { ref, computed } from "vue";
import type { Server } from "~/composables/pyroServers"; import type { Server } from "~/composables/pyroServers";
const props = defineProps<{ const props = defineProps<{
server: Server<["general", "mods", "backups", "network", "startup", "ws", "fs"]>; server: Server<["general", "content", "backups", "network", "startup", "ws", "fs"]>;
isServerRunning: boolean; isServerRunning: boolean;
}>(); }>();

View File

@ -102,10 +102,10 @@
<ButtonStyled v-if="hasMods" color="brand" type="outlined"> <ButtonStyled v-if="hasMods" color="brand" type="outlined">
<nuxt-link <nuxt-link
class="w-full text-nowrap sm:w-fit" class="w-full text-nowrap sm:w-fit"
:to="`/${type}s?sid=${props.server.serverId}`" :to="`/${type.toLocaleLowerCase()}s?sid=${props.server.serverId}`"
> >
<PlusIcon /> <PlusIcon />
Add {{ type }} Add {{ type.toLocaleLowerCase() }}
</nuxt-link> </nuxt-link>
</ButtonStyled> </ButtonStyled>
</div> </div>
@ -241,9 +241,9 @@
<p class="m-0 font-bold text-contrast">No {{ type }}s found!</p> <p class="m-0 font-bold text-contrast">No {{ type }}s found!</p>
<p class="m-0">Add some {{ type }}s to your server to manage them here.</p> <p class="m-0">Add some {{ type }}s to your server to manage them here.</p>
<ButtonStyled color="brand"> <ButtonStyled color="brand">
<NuxtLink :to="`/${type}s?sid=${props.server.serverId}`"> <NuxtLink :to="`/${type.toLocaleLowerCase()}s?sid=${props.server.serverId}`">
<PlusIcon /> <PlusIcon />
Add {{ type }} Add {{ type.toLocaleLowerCase() }}
</NuxtLink> </NuxtLink>
</ButtonStyled> </ButtonStyled>
</div> </div>
@ -299,7 +299,7 @@ const props = defineProps<{
const type = computed(() => { const type = computed(() => {
const loader = props.server.general?.loader?.toLowerCase(); const loader = props.server.general?.loader?.toLowerCase();
return loader === "paper" || loader === "purpur" ? "plugin" : "mod"; return loader === "paper" || loader === "purpur" ? "Plugin" : "Mod";
}); });
interface Mod { interface Mod {
@ -460,7 +460,10 @@ async function removeMod(mod: Mod) {
mod.changing = true; mod.changing = true;
try { try {
await props.server.content?.remove(type.value, `/${type.value}s/${mod.filename}`); await props.server.content?.remove(
type.value as "Mod" | "Plugin",
`/${type.value.toLowerCase()}s/${mod.filename}`,
);
await props.server.refresh(["general", "content"]); await props.server.refresh(["general", "content"]);
} catch (error) { } catch (error) {
console.error("Error removing mod:", error); console.error("Error removing mod:", error);

View File

@ -198,7 +198,7 @@ type ServerProps = {
exit_code?: number; exit_code?: number;
}; };
isServerRunning: boolean; isServerRunning: boolean;
server: Server<["general", "mods", "backups", "network", "startup", "ws", "fs"]>; server: Server<["general", "content", "backups", "network", "startup", "ws", "fs"]>;
}; };
const props = defineProps<ServerProps>(); const props = defineProps<ServerProps>();

View File

@ -703,7 +703,7 @@ watch(selectedMCVersion, async () => {
}); });
const onShow = () => { const onShow = () => {
selectedMCVersion.value = ""; selectedMCVersion.value = props.server.general?.mc_version || "";
selectedLoaderVersion.value = ""; selectedLoaderVersion.value = "";
}; };

View File

@ -1,5 +1,5 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
module.exports = { const config = {
content: [ content: [
"./src/components/**/*.{js,vue,ts}", "./src/components/**/*.{js,vue,ts}",
"./src/layouts/**/*.vue", "./src/layouts/**/*.vue",
@ -152,3 +152,5 @@ module.exports = {
preflight: false, preflight: false,
}, },
}; };
export default config;