Big progress

This commit is contained in:
hfcRed
2025-12-26 20:26:22 +01:00
parent 9239a72374
commit 4cda297d9d
41 changed files with 401 additions and 353 deletions

View File

@@ -1,14 +1,7 @@
.addNewButton {
--picture-size: 18px;
--icon-size: 14px;
--button-height: 28px;
--border-width: 2px;
--inner-border-radius: 6px;
padding-block: 0 !important;
padding-inline: 0 !important;
background-color: transparent !important;
height: var(--button-height);
padding: 0;
height: var(--input-height-small);
overflow: hidden;
}
.iconsContainer {
@@ -17,32 +10,24 @@
align-items: center;
justify-content: center;
background-color: var(--color-accent-low);
height: calc(var(--button-height) - var(--border-width) * 2);
border-radius: var(--inner-border-radius) 0 0 var(--inner-border-radius);
height: 100%;
padding-inline: var(--s-1);
}
.iconsContainer > svg {
max-width: var(--icon-size);
max-height: var(--icon-size);
min-width: var(--icon-size);
min-height: var(--icon-size);
width: calc(var(--input-height-small) / 2);
color: var(--color-text-accent);
stroke-width: 4px;
}
.iconsContainer > picture {
max-width: var(--picture-size);
max-height: var(--picture-size);
min-width: var(--picture-size);
min-height: var(--picture-size);
width: fit-content;
}
.textContainer {
padding-inline: var(--s-1-5);
background-color: var(--color-text-accent) !important;
height: calc(var(--button-height) - var(--border-width) * 2);
height: 100%;
display: flex;
align-items: center;
border-radius: 0 var(--inner-border-radius) var(--inner-border-radius) 0;
}

View File

@@ -95,7 +95,6 @@ export function CustomizedColorsInput({
<div>{t(`custom.colors.${cssVar}`)}</div>
<input
type="color"
className="plain"
value={colors[cssVar] ?? "#000000"}
onChange={(e) => {
const extras: Record<string, string> = {};

View File

@@ -53,6 +53,7 @@ export function Input({
>
{leftAddon ? <div className="input-addon">{leftAddon}</div> : null}
<input
className="in-container"
name={name}
id={id}
minLength={minLength}

View File

@@ -11,16 +11,18 @@
cursor: pointer;
font-size: var(--fonts-sm);
font-weight: var(--bold);
line-height: 1.2;
outline-offset: 2px;
padding-block: var(--s-1-5);
padding-inline: var(--s-2-5);
line-height: var(--input-line-height);
padding: 0 var(--input-padding-inline);
user-select: none;
outline-color: var(--color-text-accent);
height: var(--input-height);
}
.button[data-focus-visible],
.button:focus-visible {
outline: 2px solid var(--color-text-accent);
outline-style: solid;
outline-width: 2px;
outline-offset: 1px;
}
.button[data-pressed],
@@ -36,7 +38,7 @@
}
.outlined {
background-color: var(--color-accent-low);
background-color: transparent;
color: var(--color-text-accent);
}
@@ -44,28 +46,39 @@
border-color: var(--color-success);
background-color: transparent;
color: var(--color-success);
outline-color: var(--color-success);
}
.outlinedDestructive {
border-color: var(--color-error);
background-color: transparent;
color: var(--color-error);
outline-color: var(--color-error);
}
.small {
font-size: var(--fonts-xs);
padding-block: var(--s-1);
padding-inline: var(--s-2);
height: var(--input-height-small);
}
.miniscule {
font-size: var(--fonts-xxs);
padding-block: var(--s-1);
padding-inline: var(--s-2);
height: var(--input-height-smaller);
}
.big {
font-size: var(--fonts-md);
padding-block: var(--s-2-5);
padding-inline: var(--s-6);
height: var(--input-height-large);
}
.minimal {
padding: 0;
padding: 0 var(--s-1);
border: none;
background-color: transparent;
color: var(--color-text-accent);
@@ -73,14 +86,15 @@
}
.minimal[data-focus-visible] {
outline: 2px solid var(--color-accent);
outline: 2px solid var(--color-text-accent);
}
.minimalSuccess {
padding: 0;
padding: 0 var(--s-1);
border: none;
background-color: transparent;
color: var(--color-success);
outline-color: var(--color-success);
}
.success {
@@ -91,13 +105,13 @@
.destructive {
border-color: var(--color-error);
background-color: transparent;
color: var(--color-error);
background-color: var(--color-error);
color: var(--color-text-inverse);
outline-color: var(--color-error);
}
.minimalDestructive {
padding: 0;
padding: 0 var(--s-1);
border: none;
background-color: transparent;
color: var(--color-error);

View File

@@ -11,9 +11,10 @@ import styles from "./Button.module.css";
type ButtonVariant =
| "primary"
| "success"
| "destructive"
| "outlined"
| "outlined-success"
| "destructive"
| "outlined-destructive"
| "minimal"
| "minimal-success"
| "minimal-destructive";
@@ -123,12 +124,14 @@ function buttonClassName({
return styles.primary;
case "success":
return styles.success;
case "destructive":
return styles.destructive;
case "outlined":
return styles.outlined;
case "outlined-success":
return styles.outlinedSuccess;
case "destructive":
return styles.destructive;
case "outlined-destructive":
return styles.outlinedDestructive;
case "minimal":
return styles.minimal;
case "minimal-success":

View File

@@ -1,4 +1,3 @@
import clsx from "clsx";
import {
Button,
DateInput,
@@ -12,10 +11,6 @@ import {
} from "react-aria-components";
import { SendouBottomTexts } from "~/components/elements/BottomTexts";
import { SendouCalendar } from "~/components/elements/Calendar";
import {
type FormFieldSize,
formFieldSizeToClassName,
} from "../form/form-utils";
import { CalendarIcon } from "../icons/Calendar";
import { SendouLabel } from "./Label";
@@ -24,23 +19,19 @@ interface SendouDatePickerProps<T extends DateValue>
label: string;
bottomText?: string;
errorText?: string;
size?: FormFieldSize;
}
export function SendouDatePicker<T extends DateValue>({
label,
errorText,
bottomText,
size,
isRequired,
...rest
}: SendouDatePickerProps<T>) {
return (
<ReactAriaDatePicker {...rest} validationBehavior="aria">
<SendouLabel required={isRequired}>{label}</SendouLabel>
<Group
className={clsx("react-aria-Group", formFieldSizeToClassName(size))}
>
<Group className="react-aria-Group">
<DateInput>{(segment) => <DateSegment segment={segment} />}</DateInput>
<Button data-testid="open-calendar-button">
<CalendarIcon />

View File

@@ -1,38 +1,30 @@
.button {
height: 1rem;
padding: var(--s-4) var(--s-3);
height: var(--input-height);
padding: 0 var(--input-padding-inline);
border: 2px solid var(--color-border);
border-radius: var(--rounded-sm);
accent-color: var(--color-accent);
background-color: var(--color-bg);
color: var(--color-text);
outline: none;
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--s-1-5);
min-width: var(--select-width);
font-size: var(--fonts-xs);
font-weight: var(--semi-bold);
letter-spacing: 0.5px;
width: 100%;
cursor: pointer;
}
.button:hover {
border-color: var(--color-border-high);
}
&[data-focus-visible],
&[aria-expanded="true"] {
outline: var(--input-focus-ring);
outline-offset: 1px;
}
.button[data-focus-visible] {
outline: 2px solid var(--color-accent);
}
.selectValue {
max-width: calc(var(--select-width) - 55px);
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
&[data-disabled] {
pointer-events: none;
cursor: not-allowed;
opacity: 0.5;
outline: none;
}
}
.selectValue[data-placeholder] {
@@ -55,12 +47,11 @@
.popover {
padding: var(--s-1);
min-width: var(--select-width);
max-width: var(--select-width);
width: var(--trigger-width);
border: 2px solid var(--color-border);
border-radius: var(--rounded);
background-color: var(--color-bg);
max-height: 250px !important;
outline: none;
display: flex;
flex-direction: column;
@@ -76,7 +67,6 @@
font-weight: var(--semi-bold);
padding: var(--s-1-5);
border-radius: var(--rounded-sm);
height: 33px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
@@ -84,7 +74,6 @@
.item[data-disabled] {
color: var(--color-text-high);
font-style: italic;
}
.itemFocused {
@@ -101,13 +90,13 @@
display: flex;
gap: var(--s-2);
border: 2px solid var(--color-border);
border-radius: var(--rounded-sm);
border-bottom: 2px solid var(--color-border);
border-radius: var(--rounded-sm) var(--rounded-sm) 0 0;
accent-color: var(--color-accent);
background-color: var(--color-bg);
color: var(--color-text);
outline: none;
padding: var(--s-1-5) var(--s-2);
padding: var(--s-2) var(--s-1-5) calc(var(--s-1) + var(--s-2)) var(--s-1-5);
margin-block-end: var(--s-1-5);
}
@@ -145,6 +134,7 @@
}
.select {
width: 100%;
position: relative;
}

View File

@@ -125,7 +125,7 @@ export function SendouSelect<T extends object>({
<SearchIcon aria-hidden className={styles.smallIcon} />
<Input
placeholder={search.placeholder}
className={clsx("plain", styles.searchInput)}
className={clsx(styles.searchInput, "in-container")}
/>
<Button className={styles.searchClearButton}>
<CrossIcon className={styles.smallIcon} />

View File

@@ -1,7 +1,6 @@
.tabListContainer {
overflow-x: auto;
overflow-y: hidden;
padding-bottom: var(--s-1);
}
.tabList {

View File

@@ -9,7 +9,7 @@
}
.toast {
background: var(--color-bg-high);
background: var(--color-info-low);
border-radius: var(--rounded);
padding: var(--s-1-5) var(--s-3);
align-items: center;
@@ -17,7 +17,7 @@
font-size: var(--fonts-xsm);
font-weight: var(--semi-bold);
gap: var(--s-1);
border: 2px solid var(--color-border);
border: 2px solid var(--color-info);
width: 250px;
outline: none;
view-transition-class: toast;
@@ -43,28 +43,42 @@
}
}
.errorToast {
border-color: var(--color-error);
}
.topRow {
display: flex;
text-transform: uppercase;
color: var(--color-text-high);
color: var(--color-info-high);
font-size: var(--fonts-xxsm);
gap: var(--s-2);
align-items: center;
margin-block-end: var(--s-1-5);
}
.errorToast {
border-color: var(--color-error);
background-color: var(--color-error-low);
.topRow {
color: var(--color-error-high);
}
}
.successToast {
border-color: var(--color-success);
background-color: var(--color-success-low);
.topRow {
color: var(--color-success-high);
}
}
.closeButton {
margin-inline-start: auto;
outline-color: var(--color-text-high) !important;
outline-color: var(--color-text) !important;
}
.closeButton svg {
width: 1rem;
fill: var(--color-text-high);
fill: var(--color-text);
}
.alertIcon {

View File

@@ -59,6 +59,7 @@ export function SendouToastRegion() {
icon={<CrossIcon />}
className={styles.closeButton}
slot="close"
size="small"
/>
</div>
<Text slot="title">{toast.content.message}</Text>

View File

@@ -120,7 +120,7 @@ export const TournamentSearch = React.forwardRef(function TournamentSearch<
>
<SearchIcon aria-hidden className={selectStyles.smallIcon} />
<Input
className={clsx("plain", selectStyles.searchInput)}
className={selectStyles.searchInput}
data-testid="tournament-search-input"
/>
<Button className={selectStyles.searchClearButton}>

View File

@@ -107,7 +107,7 @@ export const UserSearch = React.forwardRef(function UserSearch<
>
<SearchIcon aria-hidden className={selectStyles.smallIcon} />
<Input
className={clsx("plain", selectStyles.searchInput)}
className={selectStyles.searchInput}
data-testid="user-search-input"
/>
<Button className={selectStyles.searchClearButton}>

View File

@@ -8,21 +8,18 @@ import {
import { dateToDateValue, dayMonthYearToDateValue } from "../../utils/dates";
import type { DayMonthYear } from "../../utils/zod";
import { SendouDatePicker } from "../elements/DatePicker";
import type { FormFieldSize } from "./form-utils";
export function DateFormField<T extends FieldValues>({
label,
name,
bottomText,
required,
size,
granularity = "day",
}: {
label: string;
name: FieldPath<T>;
bottomText?: string;
required?: boolean;
size?: FormFieldSize;
granularity?: "day" | "minute";
}) {
const methods = useFormContext();
@@ -54,7 +51,6 @@ export function DateFormField<T extends FieldValues>({
isRequired={required}
errorText={error?.message as string | undefined}
value={getValue()}
size={size}
isInvalid={invalid}
name={name}
onBlur={onBlur}

View File

@@ -7,7 +7,6 @@ import {
} from "react-hook-form";
import { FormMessage } from "~/components/FormMessage";
import { Label } from "~/components/Label";
import { type FormFieldSize, formFieldSizeToClassName } from "./form-utils";
export function InputFormField<T extends FieldValues>({
label,
@@ -15,7 +14,6 @@ export function InputFormField<T extends FieldValues>({
bottomText,
placeholder,
required,
size = "small",
type,
}: {
label: string;
@@ -23,7 +21,6 @@ export function InputFormField<T extends FieldValues>({
bottomText?: string;
placeholder?: string;
required?: boolean;
size?: FormFieldSize;
type?: React.HTMLInputTypeAttribute;
}) {
const methods = useFormContext();
@@ -41,7 +38,6 @@ export function InputFormField<T extends FieldValues>({
placeholder={placeholder}
type={type}
{...methods.register(name)}
className={formFieldSizeToClassName(size)}
/>
{error && (
<FormMessage type="error">{error.message as string}</FormMessage>

View File

@@ -7,21 +7,18 @@ import {
} from "react-hook-form";
import { FormMessage } from "~/components/FormMessage";
import { Label } from "~/components/Label";
import { type FormFieldSize, formFieldSizeToClassName } from "./form-utils";
export function SelectFormField<T extends FieldValues>({
label,
name,
values,
bottomText,
size,
required,
}: {
label: string;
name: FieldPath<T>;
values: Array<{ value: string | number; label: string }>;
bottomText?: string;
size?: FormFieldSize;
required?: boolean;
}) {
const methods = useFormContext();
@@ -34,11 +31,7 @@ export function SelectFormField<T extends FieldValues>({
<Label htmlFor={id} required={required}>
{label}
</Label>
<select
{...methods.register(name)}
id={id}
className={formFieldSizeToClassName(size)}
>
<select {...methods.register(name)} id={id}>
{values.map((option) => (
<option key={option.value} value={option.value}>
{option.label}

View File

@@ -1,11 +0,0 @@
import clsx from "clsx";
export type FormFieldSize = "extra-small" | "small" | "medium";
export function formFieldSizeToClassName(size?: FormFieldSize) {
return clsx({
"input__extra-small": size === "extra-small",
input__small: size === "small",
input__medium: size === "medium",
});
}

View File

@@ -119,7 +119,6 @@ function ImageUpload({
<label htmlFor={id}>{t("common:upload.imageToUpload")}</label>
<input
id={id}
className="plain"
type="file"
name="img"
accept="image/png, image/jpeg, image/jpg, image/webp"

View File

@@ -65,7 +65,7 @@ export default function BadgesPageLayout() {
<Outlet />
<Input
className="badges-search__input"
icon={<SearchIcon className="badges-search__icon" />}
icon={<SearchIcon />}
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>

View File

@@ -9,6 +9,7 @@
}
.tag {
cursor: pointer;
border: 2px solid var(--tag-color);
border-radius: var(--rounded-sm);
font-size: var(--fonts-sm);

View File

@@ -747,7 +747,6 @@ function AvatarImageInput({
<Label htmlFor="avatarImage">Logo</Label>
<input
id="avatarImage"
className="plain"
type="file"
name="img"
accept="image/png, image/jpeg, image/jpg, image/webp"

View File

@@ -80,6 +80,10 @@ function ButtonsSection() {
<SendouButton variant="success">Success Button</SendouButton>
</ComponentRow>
<ComponentRow label="Destructive">
<SendouButton variant="destructive">Destructive Button</SendouButton>
</ComponentRow>
<ComponentRow label="Outlined">
<SendouButton variant="outlined">Outlined Button</SendouButton>
</ComponentRow>
@@ -90,8 +94,10 @@ function ButtonsSection() {
</SendouButton>
</ComponentRow>
<ComponentRow label="Destructive">
<SendouButton variant="destructive">Destructive Button</SendouButton>
<ComponentRow label="Outlined Destructive">
<SendouButton variant="outlined-destructive">
Outlined Destructive
</SendouButton>
</ComponentRow>
<ComponentRow label="Minimal">
@@ -244,6 +250,10 @@ function InputsSection() {
/>
</ComponentRow>
<ComponentRow label="Textarea">
<textarea placeholder="Enter text..." aria-label="Textarea" />
</ComponentRow>
<Divider smallText>Labels</Divider>
<ComponentRow label="With Label">
@@ -387,7 +397,6 @@ function SelectSection() {
<ComponentRow label="HTML Select">
<select>
<option value="">Select...</option>
{SELECT_ITEMS.map((item) => (
<option key={item.id} value={item.id}>
{item.name}

View File

@@ -65,7 +65,6 @@ export default function FileUploadPage() {
<label htmlFor="img-field">{t("common:upload.imageToUpload")}</label>
<input
id="img-field"
className="plain"
type="file"
name="img"
accept="image/png, image/jpeg, image/webp"

View File

@@ -32,14 +32,14 @@
border-radius: 100%;
width: 30px;
height: 30px;
background-color: var(--color-bg-higher);
background-color: var(--color-bg-high);
display: grid;
place-items: center;
position: relative;
}
.item:hover .imageContainer {
outline: 3px solid var(--color-accent-low);
outline: 3px solid var(--color-bg-higher);
}
.item:focus-within .imageContainer {

View File

@@ -110,9 +110,7 @@ export default function ObjectDamagePage() {
</div>
{multiShotCount ? (
<div className="stack sm horizontal items-center label-no-spacing">
<label className="plain" htmlFor="multi">
×{multiShotCount}
</label>
<label htmlFor="multi">×{multiShotCount}</label>
<SendouSwitch
id="multi"
isSelected={isMultiShot}

View File

@@ -105,13 +105,11 @@ function FiltersForm({
label={t("scrims:filters.weekdayStart")}
name={"weekdayTimes.start" as const}
type="time"
size="extra-small"
/>
<InputFormField<ScrimFilters>
label={t("scrims:filters.weekdayEnd")}
name={"weekdayTimes.end" as const}
type="time"
size="extra-small"
/>
</div>
@@ -120,13 +118,11 @@ function FiltersForm({
label={t("scrims:filters.weekendStart")}
name={"weekendTimes.start" as const}
type="time"
size="extra-small"
/>
<InputFormField<ScrimFilters>
label={t("scrims:filters.weekendEnd")}
name={"weekendTimes.end" as const}
type="time"
size="extra-small"
/>
</div>

View File

@@ -70,14 +70,12 @@ export default function NewScrimPage() {
<WithFormField usersTeams={data.teams} />
<DateFormField<FormFields>
size="medium"
label={t("scrims:forms.when.title")}
name="at"
bottomText={t("scrims:forms.when.explanation")}
granularity="minute"
/>
<SelectFormField<FormFields>
size="medium"
label={t("scrims:forms.rangeEnd.title")}
name="rangeEnd"
bottomText={t("scrims:forms.rangeEnd.explanation")}

View File

@@ -1,4 +0,0 @@
.input {
--input-width: 11rem;
width: 11rem;
}

View File

@@ -14,7 +14,6 @@ import {
sendouQInviteLink,
} from "~/utils/urls";
import type { SendouQPreparingAction } from "../actions/q.preparing.server";
import styles from "./MemberAdder.module.css";
export function MemberAdder({
inviteCode,
@@ -57,7 +56,6 @@ export function MemberAdder({
value={inviteLink}
readOnly
id="invite"
className={styles.input}
/>
<SendouButton
variant={copySuccess ? "outlined-success" : "outlined"}
@@ -102,7 +100,7 @@ function TrusterDropdown({
const { trusters, teams } = useTrusted();
if (!trusters || trusters.length === 0) {
return <select name="id" id="players" disabled className={styles.input} />;
return <select name="id" id="players" disabled />;
}
const trustersNotInGroup = trusters.filter(
@@ -126,7 +124,6 @@ function TrusterDropdown({
onChange={(e) =>
setTruster(e.target.value ? Number(e.target.value) : undefined)
}
className={styles.input}
>
<option value="">{t("q:looking.groups.adder.select")}</option>
{teams?.map((team) => {

View File

@@ -126,7 +126,7 @@ function InfoText() {
return (
<fetcher.Form
method="post"
className="text-xs text-lighter ml-auto text-error stack horizontal sm"
className="text-xs text-lighter ml-auto text-error stack horizontal sm items-center"
>
{t("q:looking.inactiveGroup")}{" "}
<SubmitButton
@@ -306,7 +306,7 @@ function Groups() {
);
const ownGroupElement = data.ownGroup ? (
<div className="stack md">
<div className="stack sm">
{!showChat && (
<ColumnHeader>{t("q:looking.columns.myGroup")}</ColumnHeader>
)}

View File

@@ -131,7 +131,6 @@ export function TierRow({ tier }: TierRowProps) {
onChange={(e) =>
handleChangeTierColor(tier.id, e.target.value)
}
className="plain"
/>
</label>
</div>

View File

@@ -436,7 +436,7 @@ function TeamRosterInputsCheckboxes({
>
<input
className={clsx(
"plain tournament-bracket__during-match-actions__checkbox",
"tournament-bracket__during-match-actions__checkbox",
{
opaque: presentational,
},

View File

@@ -824,7 +824,6 @@ function TournamentLogoUpload({
return (
<input
id="img-field"
className="plain"
type="file"
name="img"
accept="image/png, image/jpeg, image/webp"

View File

@@ -143,7 +143,6 @@ function InGameNameInputs() {
<Label>{t("user:ign")}</Label>
<div className="stack horizontal sm items-center">
<Input
className={styles.inGameNameText}
name="inGameNameText"
aria-label="In game name"
maxLength={USER.IN_GAME_NAME_TEXT_MAX_LENGTH}
@@ -172,7 +171,7 @@ function SensSelects() {
const data = useLoaderData<typeof loader>();
return (
<div className="stack horizontal md">
<div className={styles.sensContainer}>
<div>
<Label htmlFor="motionSens">{t("user:motionSens")}</Label>
<select
@@ -307,7 +306,7 @@ function WeaponPoolSelect() {
<div className="stack horizontal sm justify-center">
{weapons.map((weapon) => {
return (
<div key={weapon.weaponSplId} className="stack xs">
<div key={weapon.weaponSplId} className="stack xs items-center">
<div className="u__weapon">
<WeaponImage
weaponSplId={weapon.weaponSplId}
@@ -404,7 +403,7 @@ function FavBadgeSelect() {
};
return (
<div>
<div className="w-full">
<input
type="hidden"
name="favoriteBadgeIds"

View File

@@ -131,7 +131,6 @@ function FormFields({ player }: { player: YT.Player | null }) {
name="video.youtubeUrl"
placeholder="https://www.youtube.com/watch?v=-dQ6JsVIKdY"
required
size="medium"
/>
<InputFormField<VodFormFields>
@@ -139,14 +138,12 @@ function FormFields({ player }: { player: YT.Player | null }) {
name="video.title"
placeholder="[SCL 47] (Grand Finals) Team Olive vs. Kraken Paradise"
required
size="medium"
/>
<DateFormField<VodFormFields>
label={t("vods:forms.title.videoDate")}
name="video.date"
required
size="extra-small"
/>
<SelectFormField<VodFormFields>

View File

@@ -52,13 +52,13 @@ import { allI18nNamespaces } from "./utils/i18n";
import { isRevalidation, metaTags } from "./utils/remix";
import { SUSPENDED_PAGE } from "./utils/urls";
import "~/styles/vars.css";
import "~/styles/normalize.css";
import "~/styles/common.css";
import "~/styles/elements.css";
import "~/styles/utils.css";
import "~/styles/flags.css";
import "~/styles/layout.css";
import "~/styles/vars.css";
import "nprogress/nprogress.css";
import clsx from "clsx";

View File

@@ -119,9 +119,3 @@
margin: 0 auto;
font-size: var(--fonts-lg);
}
.badges-search__icon {
height: 25px;
margin: auto;
margin-right: 15px;
}

View File

@@ -5,10 +5,6 @@
overflow-wrap: break-word;
}
*:focus:not(:focus-visible):not([data-focus-visible]) {
outline: none !important;
}
html {
color-scheme: light dark;
accent-color: var(--color-accent);
@@ -70,107 +66,187 @@ a {
}
/* :not([name="text"]) workaround not to select textarea on map planner */
textarea:not(.plain, [name="text"]) {
width: 18rem;
max-width: 100%;
height: 8rem;
padding: var(--s-2-5) var(--s-3);
textarea:not([name="text"]) {
width: 100%;
min-height: 5rem;
padding: var(--input-padding-block) var(--input-padding-inline);
line-height: var(--input-line-height);
border: 2px solid var(--color-border);
border-radius: var(--rounded-sm);
accent-color: var(--color-accent);
background-color: var(--color-bg);
color: var(--color-text);
outline: none;
overflow-wrap: normal;
overflow-x: auto;
resize: vertical;
&:focus-within {
outline: var(--input-focus-ring);
outline-offset: 1px;
}
}
textarea:not(.plain, [name="text"]):hover {
border-color: var(--color-border-high);
}
textarea:not(.plain, [name="text"]):focus-within {
border-color: transparent;
outline: 2px solid var(--color-text-accent);
}
input:not(.plain, [type="radio"]) {
width: var(--input-width, 12rem);
}
input:not(.plain) {
height: 1rem;
padding: var(--s-4) var(--s-3);
.input-container {
display: flex;
font-size: var(--fonts-sm);
outline: none;
line-height: var(--input-line-height);
border: 2px solid var(--color-border);
border-radius: var(--rounded-sm);
accent-color: var(--color-accent);
background-color: var(--color-bg);
color: var(--color-text);
height: var(--input-height);
width: 100%;
& svg {
color: var(--color-text-high);
height: calc(var(--input-height) / 2);
margin: auto;
margin-right: 15px;
}
&:has(input:user-invalid) {
outline: var(--input-focus-ring-error);
outline-offset: 1px;
}
&:focus-within {
outline: var(--input-focus-ring);
outline-offset: 1px;
}
&.input__read-only {
pointer-events: none;
cursor: not-allowed;
opacity: 0.5;
outline: none;
}
input {
border-radius: var(--rounded-sm);
padding: 0 var(--input-padding-inline);
outline: none;
width: 100%;
background-color: inherit;
border: none;
&::placeholder {
color: var(--color-text-high);
}
}
}
input:not(.in-container) {
width: 100%;
box-sizing: border-box;
border: 2px solid var(--color-border);
border-radius: var(--rounded-sm);
background: var(--color-bg);
padding: 0 var(--input-padding-inline);
height: var(--input-height);
line-height: var(--input-line-height);
outline: none;
}
input:not(.plain):hover {
border-color: var(--color-border-high);
}
&::placeholder {
color: var(--color-text-high);
}
input:user-invalid {
border-color: transparent;
outline: 2px solid var(--color-error);
}
&:disabled {
pointer-events: none;
cursor: not-allowed;
opacity: 0.5;
outline: none;
}
.input__read-only {
cursor: not-allowed;
opacity: 0.5;
}
.input__extra-small {
min-width: var(--input-width-extra-small);
max-width: var(--input-width-extra-small);
}
.input__small {
min-width: var(--input-width-small);
max-width: var(--input-width-small);
}
.input__medium {
min-width: var(--input-width-medium);
max-width: var(--input-width-medium);
}
input:not(.plain, .combobox-input):focus-within {
border-color: transparent;
outline: 2px solid var(--color-text-accent);
}
input:not(.plain)::placeholder {
color: var(--color-text-high);
font-size: var(--fonts-xxs);
font-weight: var(--semi-bold);
letter-spacing: 0.5px;
}
input:not(.plain).error {
border-color: transparent;
outline: 2px solid var(--color-error);
&:focus-within {
outline: var(--input-focus-ring);
outline-offset: 1px;
}
}
input[type="checkbox"] {
width: 16px;
height: 16px;
appearance: none;
cursor: pointer;
padding: 0;
width: var(--toggle-height-small);
height: var(--toggle-height-small);
border-radius: 5px;
background-color: var(--color-bg);
border: 2px solid var(--color-border);
&::after {
content: "";
display: none;
width: 100%;
height: 100%;
font-size: 1rem;
line-height: 0.75;
background-color: var(--color-text-inverse);
border-width: 0 2px 2px 0;
margin: 0;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
rotate: 45deg;
}
&:focus-within {
outline: none;
}
&:focus-visible {
outline: var(--input-focus-ring);
outline-offset: 1px;
}
&:checked {
border-color: var(--color-text-accent);
background-color: var(--color-text-accent);
&::after {
display: block;
}
}
}
input[type="radio"] {
appearance: none;
cursor: pointer;
vertical-align: middle;
width: var(--toggle-height-small);
height: var(--toggle-height-small);
background-color: var(--color-bg);
border: 2px solid var(--color-border);
border-radius: 999999px;
padding: 0;
&:focus-within {
outline: none;
}
&:focus-visible {
outline: var(--input-focus-ring);
outline-offset: 1px;
}
&::after {
content: "";
display: block;
width: 50%;
height: 50%;
border-radius: 999999px;
background-color: var(--color-bg);
margin: auto;
margin-top: 25%;
}
&:checked {
border-color: var(--color-text-accent);
&::after {
background-color: var(--color-text-accent);
}
}
}
[list]::-webkit-calendar-picker-indicator {
display: none !important;
}
input[type="time"]::-webkit-calendar-picker-indicator {
filter: invert(1);
opacity: 0.55;
cursor: pointer;
}
label {
display: block;
font-size: var(--fonts-xs);
@@ -228,49 +304,82 @@ select {
box-sizing: border-box;
border: 2px solid var(--color-border);
border-radius: var(--rounded-sm);
background: var(--select-background, var(--color-bg));
background: var(--color-bg);
background-image: url('data:image/svg+xml;utf8,<svg width="17px" color="rgb(255 255 255 / 55%)" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M19 9l-7 7-7-7" /></svg>');
background-position: center right var(--s-3);
background-position: center right 15px;
background-repeat: no-repeat;
cursor: pointer;
padding-inline: var(--s-3) var(--s-9);
padding-block: 3.5px;
-moz-appearance: none;
-webkit-appearance: none;
padding: 0 var(--input-padding-inline);
height: var(--input-height);
line-height: var(--input-line-height);
display: inline-flex;
align-items: center;
text-overflow: ellipsis;
white-space: nowrap;
appearance: none;
height: 2rem;
line-height: 1.25;
}
overflow: hidden;
select:disabled {
cursor: not-allowed;
opacity: 0.5;
transform: initial;
}
@supports (appearance: base-select) {
appearance: base-select;
}
select:hover {
border-color: var(--color-border-high);
&:disabled {
pointer-events: none;
cursor: not-allowed;
opacity: 0.5;
outline: none;
}
&:focus-within {
outline: var(--input-focus-ring);
outline-offset: 1px;
}
/* biome-ignore lint: experimental CSS feature */
&::picker(select) {
@supports (appearance: base-select) {
appearance: base-select;
}
background-color: var(--color-bg);
border: 2px solid var(--color-border);
border-radius: var(--rounded-sm);
padding: var(--s-1);
margin: 0.5rem;
translate: -0.5rem;
max-height: 50dvh;
}
/* biome-ignore lint: experimental CSS feature */
&::picker-icon {
display: none;
}
option {
background-color: var(--color-bg);
color: var(--color-text);
border-radius: var(--rounded-sm);
font-size: var(--fonts-xsm);
font-weight: var(--semi-bold);
padding: var(--s-1-5);
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
&[disabled] {
color: var(--color-text-high);
}
&:hover:not([disabled]) {
background-color: var(--color-bg-high);
}
}
}
.light select {
background-image: url('data:image/svg+xml;utf8,<svg width="17px" color="rgb(0 0 0 / 55%)" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" /></svg>');
}
.light input[type="time"]::-webkit-calendar-picker-indicator {
filter: invert(0);
opacity: 0.55;
}
select::selection {
overflow: hidden;
font-weight: bold;
}
select:focus {
border-color: transparent;
outline: 2px solid var(--color-text-accent);
}
.my-table {
width: 100%;
border-collapse: separate;
@@ -338,36 +447,6 @@ abbr[title] {
margin-block-end: 0.125rem;
}
.input-container {
display: flex;
border: 2px solid var(--color-border);
border-radius: var(--rounded-sm);
accent-color: var(--color-accent);
background-color: var(--color-bg);
color: var(--color-text);
font-size: var(--fonts-sm);
outline: none;
}
.input-container:hover {
border-color: var(--color-border-high);
}
.input-container:focus-within {
border-color: transparent;
outline: 2px solid var(--color-text-accent);
}
.input-container > input {
width: 100%;
border: none;
margin: auto 0;
}
.input-container > input:focus-within {
outline: none;
}
.input-addon {
display: grid;
border-radius: var(--rounded-xs) 0 0 var(--rounded-xs);
@@ -456,6 +535,11 @@ abbr[title] {
display: flex;
align-items: center;
justify-content: center;
&:focus-visible {
outline: var(--input-focus-ring);
outline-offset: 1px;
}
}
.react-aria-Button.info-popover__trigger__tiny {
@@ -553,15 +637,18 @@ abbr[title] {
}
.alert.warning {
background-color: var(--color-warning-high);
background-color: var(--color-warning-low);
color: var(--color-warning-high);
}
.alert.error {
background-color: var(--color-error);
background-color: var(--color-error-low);
color: var(--color-error-high);
}
.alert.success {
background-color: var(--color-success-high);
background-color: var(--color-success-low);
color: var(--color-success-high);
}
.avatar {

View File

@@ -138,6 +138,9 @@
}
.react-aria-Switch {
--height: var(--toggle-height);
cursor: pointer;
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
@@ -147,51 +150,40 @@
font-size: var(--fonts-xs);
font-weight: var(--bold);
margin-block-end: 0;
&.small {
--height: var(--toggle-height-small);
}
}
.react-aria-Switch .indicator {
width: var(--s-11);
height: var(--s-6);
background: var(--color-bg-higher);
border-radius: 1.143rem;
}
width: calc(var(--height) * 1.75);
height: var(--height);
background: var(--color-bg);
border: 2px solid var(--color-border);
border-radius: 99999px;
.react-aria-Switch.small .indicator {
width: 2rem;
height: 1.143rem;
}
.react-aria-Switch .indicator:before {
content: "";
display: block;
margin: 0.26rem;
width: var(--s-4);
height: var(--s-4);
background: white;
border-radius: 16px;
transition: transform 200ms;
}
.react-aria-Switch.small .indicator:before {
width: 0.857rem;
height: 0.857rem;
margin: 0.143rem;
}
.react-aria-Switch[data-pressed] .indicator:before {
opacity: 0.8;
&:before {
content: "";
display: block;
margin: 2px;
width: calc(var(--height) - 8px);
height: calc(var(--height) - 8px);
aspect-ratio: 1 / 1;
background: var(--color-border);
border-radius: 50%;
transition: transform 200ms;
}
}
.react-aria-Switch[data-selected] .indicator {
background: var(--color-text-accent);
}
border-color: var(--color-text-accent);
.react-aria-Switch[data-selected] .indicator:before {
transform: translateX(125%);
}
.react-aria-Switch.small[data-selected] .indicator:before {
transform: translateX(100%);
&:before {
transform: translateX(calc(var(--height) * 0.75));
background: var(--color-text-inverse);
}
}
.react-aria-Switch[data-focus-visible] .indicator {

View File

@@ -6,24 +6,29 @@
gap: var(--s-6);
}
.inGameNameText {
max-width: 8rem;
}
.inGameNameHashtag {
font-size: var(--fonts-lg);
}
.inGameNameDiscriminator {
width: 5rem;
min-width: 5rem;
flex: 1;
}
.sensContainer {
width: 100%;
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--s-4);
}
.sensSelect {
width: 6rem;
min-width: 100%;
flex: 1;
}
.weaponPool {
width: 20rem;
width: 100%;
}
.bioContainer {

View File

@@ -31,7 +31,7 @@ html.dark {
--color-info: oklch(52% 0.27 275);
--color-info-high: oklch(83% 0.08 275);
--color-success-low: oklch(39% 0.08 135);
--color-success-low: oklch(35% 0.08 135);
--color-success: oklch(85% 0.22 135);
--color-success-high: oklch(91% 0.12 135);
@@ -93,6 +93,19 @@ html {
--border-style: 1px solid var(--color-border);
--backdrop-filter: blur(10px) brightness(95%);
--input-height-smaller: 1rem;
--input-height-small: 2rem;
--input-height: 2.5rem;
--input-height-large: 3rem;
--input-padding-block: 0.5rem;
--input-padding-inline: 1rem;
--input-line-height: 1.2rem;
--input-focus-ring: 2px solid var(--color-text-accent);
--input-focus-ring-error: 2px solid var(--color-error);
--toggle-height: 1.5rem;
--toggle-height-small: 1.25rem;
}
html {