feat: styles

This commit is contained in:
2026-07-09 09:25:11 +02:00
parent 5518acd719
commit cf7f68cff7
4 changed files with 129 additions and 41 deletions
-1
View File
@@ -7,7 +7,6 @@ Site Next.js pour les services de `leonmorival.xyz`.
La page Minecraft contient un formulaire de candidature. Une demande valide envoie uniquement une notification dans le webhook configure avec : La page Minecraft contient un formulaire de candidature. Une demande valide envoie uniquement une notification dans le webhook configure avec :
- le pseudo Minecraft ; - le pseudo Minecraft ;
- l'identifiant Discord renseigne ;
- le message du joueur. - le message du joueur.
Le site ne modifie pas directement la whitelist Minecraft. Le site ne modifie pas directement la whitelist Minecraft.
+1 -15
View File
@@ -20,7 +20,6 @@ export default function MinecraftWhitelistForm() {
const formData = new FormData(form); const formData = new FormData(form);
const payload = { const payload = {
username: String(formData.get("username") ?? ""), username: String(formData.get("username") ?? ""),
discord: String(formData.get("discord") ?? ""),
reason: String(formData.get("reason") ?? ""), reason: String(formData.get("reason") ?? ""),
}; };
@@ -59,7 +58,7 @@ export default function MinecraftWhitelistForm() {
return ( return (
<form className="whitelist-form block-panel" onSubmit={submitRequest}> <form className="whitelist-form block-panel" onSubmit={submitRequest}>
<div className="form-field"> <div className="form-field form-field--full">
<label htmlFor="minecraft-username">Pseudo Minecraft</label> <label htmlFor="minecraft-username">Pseudo Minecraft</label>
<input <input
id="minecraft-username" id="minecraft-username"
@@ -74,19 +73,6 @@ export default function MinecraftWhitelistForm() {
/> />
</div> </div>
<div className="form-field">
<label htmlFor="minecraft-discord">Discord</label>
<input
id="minecraft-discord"
name="discord"
type="text"
autoComplete="off"
maxLength={64}
placeholder="leon"
required
/>
</div>
<div className="form-field form-field--full"> <div className="form-field form-field--full">
<label htmlFor="minecraft-reason">Message</label> <label htmlFor="minecraft-reason">Message</label>
<textarea <textarea
+127 -16
View File
@@ -608,6 +608,7 @@ svg {
z-index: 2; z-index: 2;
display: flex; display: flex;
width: min(860px, 100%); width: min(860px, 100%);
min-width: 0;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
text-align: center; text-align: center;
@@ -645,6 +646,7 @@ svg {
.server-address { .server-address {
display: inline-flex; display: inline-flex;
max-width: 100%; max-width: 100%;
min-width: 0;
padding: 18px 24px; padding: 18px 24px;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -667,6 +669,7 @@ svg {
.minecraft-actions { .minecraft-actions {
display: flex; display: flex;
max-width: 100%;
margin-top: 22px; margin-top: 22px;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
@@ -680,6 +683,8 @@ svg {
.back-home-link { .back-home-link {
display: inline-flex; display: inline-flex;
min-height: 58px; min-height: 58px;
max-width: 100%;
min-width: 0;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 12px; gap: 12px;
@@ -691,10 +696,23 @@ svg {
font-family: var(--font-pixel), var(--font-geist-mono), monospace; font-family: var(--font-pixel), var(--font-geist-mono), monospace;
font-size: 0.82rem; font-size: 0.82rem;
line-height: 1.25; line-height: 1.25;
text-align: center;
text-decoration: none; text-decoration: none;
transition: transform 160ms ease, box-shadow 160ms ease; transition: transform 160ms ease, box-shadow 160ms ease;
} }
.copy-address-button span,
.map-button span,
.large-map-link span,
.back-home-link span,
.minecraft-brand span,
.minecraft-nav-links a,
.service-copy,
.service-action-label {
min-width: 0;
overflow-wrap: anywhere;
}
.copy-address-button:hover, .copy-address-button:hover,
.map-button:hover, .map-button:hover,
.large-map-link:hover, .large-map-link:hover,
@@ -845,6 +863,7 @@ h2.pixel-heading {
.form-field { .form-field {
display: grid; display: grid;
min-width: 0;
gap: 10px; gap: 10px;
} }
@@ -923,6 +942,7 @@ h2.pixel-heading {
.whitelist-message { .whitelist-message {
display: flex; display: flex;
min-height: 58px; min-height: 58px;
min-width: 0;
margin: 0; margin: 0;
padding: 12px 16px; padding: 12px 16px;
align-items: center; align-items: center;
@@ -932,6 +952,7 @@ h2.pixel-heading {
font-family: var(--font-geist-mono), monospace; font-family: var(--font-geist-mono), monospace;
font-size: 1rem; font-size: 1rem;
line-height: 1.35; line-height: 1.35;
overflow-wrap: anywhere;
} }
.whitelist-message--success { .whitelist-message--success {
@@ -1130,6 +1151,11 @@ h2.pixel-heading {
} }
@media (max-width: 700px) { @media (max-width: 700px) {
.minecraft-page,
.astroneer-page {
--shadow-hard: 4px 4px 0 rgb(0 0 0 / 55%);
}
.home-shell { .home-shell {
width: min(100% - 24px, 520px); width: min(100% - 24px, 520px);
padding-top: 24px; padding-top: 24px;
@@ -1172,11 +1198,21 @@ h2.pixel-heading {
} }
.minecraft-page { .minecraft-page {
font-size: 1.2rem; font-size: 1.05rem;
} }
.astroneer-page { .astroneer-page {
font-size: 1.2rem; font-size: 1.05rem;
}
.minecraft-nav {
width: min(100% - 20px, 520px);
gap: 0;
}
.minecraft-brand {
padding: 12px 14px;
font-size: 0.68rem;
} }
.minecraft-nav-links { .minecraft-nav-links {
@@ -1184,40 +1220,57 @@ h2.pixel-heading {
} }
.minecraft-nav-links a { .minecraft-nav-links a {
font-size: 0.58rem; min-height: 44px;
padding: 0 10px;
font-size: 0.52rem;
line-height: 1.25;
text-align: center;
} }
.minecraft-hero { .minecraft-hero {
min-height: 720px; min-height: 720px;
padding-right: 16px; padding-right: 14px;
padding-left: 16px; padding-left: 14px;
} }
.astroneer-hero { .astroneer-hero {
min-height: 720px; min-height: 720px;
padding-right: 16px; padding-right: 14px;
padding-left: 16px; padding-left: 14px;
} }
.minecraft-hero-content h1 { .minecraft-hero-content h1 {
font-size: 2.45rem; max-width: 100%;
font-size: 1.95rem;
line-height: 1.22;
overflow-wrap: anywhere;
} }
.minecraft-hero-content p { .minecraft-hero-content p {
font-size: 1.42rem; font-size: 1.12rem;
line-height: 1.45;
} }
.server-address { .server-address {
padding: 16px; width: 100%;
font-size: 0.88rem; padding: 14px 12px;
gap: 10px;
font-size: 0.68rem;
line-height: 1.35;
}
.server-address svg {
width: 26px;
min-width: 26px;
height: 26px;
} }
.astroneer-orbit { .astroneer-orbit {
width: 540px; width: min(420px, 118vw);
} }
.astroneer-planet { .astroneer-planet {
width: 230px; width: 190px;
} }
.minecraft-actions, .minecraft-actions,
@@ -1237,6 +1290,32 @@ h2.pixel-heading {
width: 100%; width: 100%;
} }
.copy-address-button,
.map-button,
.large-map-link,
.back-home-link,
.whitelist-submit {
min-height: 52px;
padding-right: 14px;
padding-left: 14px;
font-size: 0.64rem;
}
.whitelist-form,
.status-panel,
.map-copy {
padding: 18px;
}
.form-field input {
min-height: 52px;
padding: 0 12px;
}
.form-field textarea {
padding: 12px;
}
.status-item, .status-item,
.status-item:nth-child(2), .status-item:nth-child(2),
.status-item:nth-child(-n + 2) { .status-item:nth-child(-n + 2) {
@@ -1250,16 +1329,48 @@ h2.pixel-heading {
.pixel-heading h2, .pixel-heading h2,
h2.pixel-heading { h2.pixel-heading {
font-size: 1.05rem; font-size: 0.9rem;
line-height: 1.35;
} }
.section-heading p, .section-heading p,
.map-copy p { .map-copy p {
font-size: 1.24rem; font-size: 1.02rem;
line-height: 1.45;
} }
.large-map-link { .large-map-link {
font-size: 0.72rem; gap: 10px;
font-size: 0.62rem;
}
}
@media (max-width: 380px) {
.home-hero h1 {
font-size: 2.35rem;
}
.minecraft-hero-content h1 {
font-size: 1.62rem;
}
.minecraft-hero-content p,
.section-heading p,
.map-copy p {
font-size: 0.95rem;
}
.minecraft-nav-links a {
font-size: 0.48rem;
}
.server-address,
.copy-address-button,
.map-button,
.large-map-link,
.back-home-link,
.whitelist-submit {
font-size: 0.56rem;
} }
} }
+1 -9
View File
@@ -1,11 +1,9 @@
export type WhitelistRequest = { export type WhitelistRequest = {
username: string; username: string;
discord: string;
reason: string; reason: string;
}; };
const usernamePattern = /^[A-Za-z0-9_]{3,16}$/; const usernamePattern = /^[A-Za-z0-9_]{3,16}$/;
const maxDiscordLength = 64;
const maxReasonLength = 800; const maxReasonLength = 800;
export function parseWhitelistRequest(payload: unknown): WhitelistRequest { export function parseWhitelistRequest(payload: unknown): WhitelistRequest {
@@ -15,22 +13,17 @@ export function parseWhitelistRequest(payload: unknown): WhitelistRequest {
const input = payload as Partial<Record<keyof WhitelistRequest, unknown>>; const input = payload as Partial<Record<keyof WhitelistRequest, unknown>>;
const username = String(input.username ?? "").trim(); const username = String(input.username ?? "").trim();
const discord = String(input.discord ?? "").trim();
const reason = String(input.reason ?? "").trim(); const reason = String(input.reason ?? "").trim();
if (!usernamePattern.test(username)) { if (!usernamePattern.test(username)) {
throw new Error("Pseudo Minecraft invalide."); throw new Error("Pseudo Minecraft invalide.");
} }
if (discord.length < 2 || discord.length > maxDiscordLength) {
throw new Error("Identifiant Discord invalide.");
}
if (reason.length < 10 || reason.length > maxReasonLength) { if (reason.length < 10 || reason.length > maxReasonLength) {
throw new Error("Message trop court ou trop long."); throw new Error("Message trop court ou trop long.");
} }
return { username, discord, reason }; return { username, reason };
} }
async function readDiscordError(response: Response) { async function readDiscordError(response: Response) {
@@ -59,7 +52,6 @@ export async function sendWhitelistRequestToDiscord(request: WhitelistRequest) {
color: 0x33e879, color: 0x33e879,
fields: [ fields: [
{ name: "Pseudo Minecraft", value: request.username, inline: true }, { name: "Pseudo Minecraft", value: request.username, inline: true },
{ name: "Discord", value: request.discord, inline: true },
{ name: "Message", value: request.reason.slice(0, maxReasonLength) }, { name: "Message", value: request.reason.slice(0, maxReasonLength) },
], ],
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),