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,108 +21,110 @@
within the last twelve (12) months:
</p>
<table>
<tr>
<th>Category</th>
<th>Examples</th>
<th>Collected</th>
</tr>
<tr>
<td>A. Identifiers.</td>
<td>
A real name, alias, postal address, unique personal identifier, online identifier,
Internet Protocol address, email address, account name, Social Security number, driver's
license number, passport number, or other similar identifiers.
</td>
<td>YES</td>
</tr>
<tr>
<td>
B. Personal information categories listed in the California Customer Records statute (Cal.
Civ. Code § 1798.80(e)).
</td>
<td>
A name, signature, Social Security number, physical characteristics or description,
address, telephone number, passport number, driver's license or state identification card
number, insurance policy number, education, employment, employment history, bank account
number, credit card number, debit card number, or any other financial information, medical
information, or health insurance information. <br /><br />
Some personal information included in this category may overlap with other categories.
</td>
<td>NO</td>
</tr>
<tr>
<td>C. Protected classification characteristics.</td>
<td>
Age (40 years or older), race, color, ancestry, national origin, citizenship, religion or
creed, marital status, medical condition, physical or mental disability, sex (including
gender, gender identity, gender expression, pregnancy or childbirth and related medical
conditions), sexual orientation, veteran or military status, genetic information
(including familial genetic information).
</td>
<td>NO</td>
</tr>
<tr>
<td>D. Commercial information.</td>
<td>
Records of personal property, products or services purchased, obtained, or considered, or
other purchasing or consuming histories or tendencies.
</td>
<td>NO</td>
</tr>
<tr>
<td>E. Biometric information.</td>
<td>
Genetic, physiological, behavioral, and biological characteristics, or activity patterns
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
physical patterns, and sleep, health, or exercise data.
</td>
<td>NO</td>
</tr>
<tr>
<td>F. Internet or other similar network activity.</td>
<td>
Browsing history, search history, information on a consumer's interaction with a website,
application, or advertisement.
</td>
<td>YES</td>
</tr>
<tr>
<td>G. Geolocation data.</td>
<td>Physical location or movements.</td>
<td>YES</td>
</tr>
<tr>
<td>H. Sensory data.</td>
<td>Audio, electronic, visual, thermal, olfactory, or similar information.</td>
<td>NO</td>
</tr>
<tr>
<td>I. Professional or employment-related information.</td>
<td>Current or past job history or performance evaluations.</td>
<td>NO</td>
</tr>
<tr>
<td>
J. Non-public education information (per the Family Educational Rights and Privacy Act (20
U.S.C. Section 1232g, 34 C.F.R. Part 99)).
</td>
<td>
Education records directly related to a student maintained by an educational institution
or party acting on its behalf, such as grades, transcripts, class lists, student
schedules, student identification codes, student financial information, or student
disciplinary records.
</td>
<td>NO</td>
</tr>
<tr>
<td>K. Inferences drawn from other personal information.</td>
<td>
Profile reflecting a person's preferences, characteristics, psychological trends,
predispositions, behavior, attitudes, intelligence, abilities, and aptitudes.
</td>
<td>NO</td>
</tr>
<tbody>
<tr>
<th>Category</th>
<th>Examples</th>
<th>Collected</th>
</tr>
<tr>
<td>A. Identifiers.</td>
<td>
A real name, alias, postal address, unique personal identifier, online identifier,
Internet Protocol address, email address, account name, Social Security number, driver's
license number, passport number, or other similar identifiers.
</td>
<td>YES</td>
</tr>
<tr>
<td>
B. Personal information categories listed in the California Customer Records statute
(Cal. Civ. Code § 1798.80(e)).
</td>
<td>
A name, signature, Social Security number, physical characteristics or description,
address, telephone number, passport number, driver's license or state identification
card number, insurance policy number, education, employment, employment history, bank
account number, credit card number, debit card number, or any other financial
information, medical information, or health insurance information. <br /><br />
Some personal information included in this category may overlap with other categories.
</td>
<td>NO</td>
</tr>
<tr>
<td>C. Protected classification characteristics.</td>
<td>
Age (40 years or older), race, color, ancestry, national origin, citizenship, religion
or creed, marital status, medical condition, physical or mental disability, sex
(including gender, gender identity, gender expression, pregnancy or childbirth and
related medical conditions), sexual orientation, veteran or military status, genetic
information (including familial genetic information).
</td>
<td>NO</td>
</tr>
<tr>
<td>D. Commercial information.</td>
<td>
Records of personal property, products or services purchased, obtained, or considered,
or other purchasing or consuming histories or tendencies.
</td>
<td>NO</td>
</tr>
<tr>
<td>E. Biometric information.</td>
<td>
Genetic, physiological, behavioral, and biological characteristics, or activity patterns
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 physical patterns, and sleep, health, or exercise data.
</td>
<td>NO</td>
</tr>
<tr>
<td>F. Internet or other similar network activity.</td>
<td>
Browsing history, search history, information on a consumer's interaction with a
website, application, or advertisement.
</td>
<td>YES</td>
</tr>
<tr>
<td>G. Geolocation data.</td>
<td>Physical location or movements.</td>
<td>YES</td>
</tr>
<tr>
<td>H. Sensory data.</td>
<td>Audio, electronic, visual, thermal, olfactory, or similar information.</td>
<td>NO</td>
</tr>
<tr>
<td>I. Professional or employment-related information.</td>
<td>Current or past job history or performance evaluations.</td>
<td>NO</td>
</tr>
<tr>
<td>
J. Non-public education information (per the Family Educational Rights and Privacy Act
(20 U.S.C. Section 1232g, 34 C.F.R. Part 99)).
</td>
<td>
Education records directly related to a student maintained by an educational institution
or party acting on its behalf, such as grades, transcripts, class lists, student
schedules, student identification codes, student financial information, or student
disciplinary records.
</td>
<td>NO</td>
</tr>
<tr>
<td>K. Inferences drawn from other personal information.</td>
<td>
Profile reflecting a person's preferences, characteristics, psychological trends,
predispositions, behavior, attitudes, intelligence, abilities, and aptitudes.
</td>
<td>NO</td>
</tr>
</tbody>
</table>
<p>Personal information does not include:</p>
<ul>

View File

@ -84,7 +84,26 @@
</button>
</ButtonStyled>
</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
v-model="serverHideInstalled"
label="Hide installed content"
@ -238,7 +257,7 @@
<button
v-if="
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
"
disabled
@ -328,6 +347,7 @@ const projectTypes = computed(() => [projectType.value.id]);
const server = ref();
const serverHideInstalled = ref(false);
const eraseDataOnInstall = ref(false);
const PERSISTENT_QUERY_PARAMS = ["sid", "shi"];
@ -342,7 +362,7 @@ async function updateServerContext() {
if (!auth.value.user) {
router.push("/auth/sign-in?redirect=" + encodeURIComponent(route.fullPath));
} 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) {
const installedMods = server.value.mods?.data
const installedMods = server.value.content?.data
.filter((x) => x.project_id)
.map((x) => x.project_id);
@ -461,7 +481,14 @@ async function serverInstall(project) {
) ?? versions[0];
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;
navigateTo(`/servers/manage/${route.query.sid}/options/loader`);
} else if (projectType.value.id === "mod") {
@ -817,4 +844,8 @@ useSeoMeta({
mask-image: linear-gradient(to bottom, black, transparent);
opacity: 0.25;
}
.stylized-toggle:checked::after {
background: var(--color-accent-contrast) !important;
}
</style>

View File

@ -86,10 +86,12 @@
</ButtonStyled>
</div>
</div>
<!-- SERVER START -->
<div
v-else-if="serverData"
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="{
'--server-bg-image': serverData.image
? `url(${serverData.image})`
@ -302,6 +304,7 @@ import {
import DOMPurify from "dompurify";
import { ButtonStyled } from "@modrinth/ui";
import { Intercom, shutdown } from "@intercom/messenger-js-sdk";
import { reloadNuxtApp } from "#app";
import type { ServerState, Stats, WSEvent, WSInstallationResultEvent } from "~/types/servers";
import { usePyroConsole } from "~/store/console.ts";

View File

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

View File

@ -102,10 +102,10 @@
<ButtonStyled v-if="hasMods" color="brand" type="outlined">
<nuxt-link
class="w-full text-nowrap sm:w-fit"
:to="`/${type}s?sid=${props.server.serverId}`"
:to="`/${type.toLocaleLowerCase()}s?sid=${props.server.serverId}`"
>
<PlusIcon />
Add {{ type }}
Add {{ type.toLocaleLowerCase() }}
</nuxt-link>
</ButtonStyled>
</div>
@ -241,9 +241,9 @@
<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>
<ButtonStyled color="brand">
<NuxtLink :to="`/${type}s?sid=${props.server.serverId}`">
<NuxtLink :to="`/${type.toLocaleLowerCase()}s?sid=${props.server.serverId}`">
<PlusIcon />
Add {{ type }}
Add {{ type.toLocaleLowerCase() }}
</NuxtLink>
</ButtonStyled>
</div>
@ -299,7 +299,7 @@ const props = defineProps<{
const type = computed(() => {
const loader = props.server.general?.loader?.toLowerCase();
return loader === "paper" || loader === "purpur" ? "plugin" : "mod";
return loader === "paper" || loader === "purpur" ? "Plugin" : "Mod";
});
interface Mod {
@ -460,7 +460,10 @@ async function removeMod(mod: Mod) {
mod.changing = true;
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"]);
} catch (error) {
console.error("Error removing mod:", error);

View File

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

View File

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

View File

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