mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-27 21:58:08 -05:00
Custom kits widget
This commit is contained in:
@@ -153,6 +153,54 @@
|
||||
background-color: var(--color-bg-high);
|
||||
}
|
||||
|
||||
.customKits {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-inline: var(--s-2);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-box);
|
||||
background-color: var(--color-bg-high);
|
||||
}
|
||||
|
||||
.customKit {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-2);
|
||||
padding-block: var(--s-2);
|
||||
|
||||
& + & {
|
||||
border-top: 1px solid var(--color-border);
|
||||
}
|
||||
}
|
||||
|
||||
.customKitWeapon {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
padding: var(--s-1-5);
|
||||
border-radius: 100%;
|
||||
background-color: var(--color-bg-higher);
|
||||
}
|
||||
|
||||
.customKitName {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: var(--font-xs);
|
||||
font-weight: var(--weight-semi);
|
||||
}
|
||||
|
||||
.customKitParts {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
gap: var(--s-1);
|
||||
}
|
||||
|
||||
.customKitPart {
|
||||
display: flex;
|
||||
padding: var(--s-1);
|
||||
border-radius: 100%;
|
||||
background-color: var(--color-bg-higher);
|
||||
}
|
||||
|
||||
.weaponGrid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));
|
||||
|
||||
@@ -6,7 +6,14 @@ import { BuildCard } from "~/components/BuildCard";
|
||||
import { Divider } from "~/components/Divider";
|
||||
import { SendouButton } from "~/components/elements/Button";
|
||||
import { SendouPopover } from "~/components/elements/Popover";
|
||||
import { Image, ModeImage, StageImage, WeaponImage } from "~/components/Image";
|
||||
import {
|
||||
Image,
|
||||
ModeImage,
|
||||
SpecialWeaponImage,
|
||||
StageImage,
|
||||
SubWeaponImage,
|
||||
WeaponImage,
|
||||
} from "~/components/Image";
|
||||
import { BskyIcon } from "~/components/icons/Bsky";
|
||||
import { DiscordIcon } from "~/components/icons/Discord";
|
||||
import { TwitchIcon } from "~/components/icons/Twitch";
|
||||
@@ -255,6 +262,10 @@ export function Widget({
|
||||
return widget.data.length === 0 ? null : (
|
||||
<WeaponPool weapons={widget.data} />
|
||||
);
|
||||
case "custom-kits":
|
||||
return widget.data.length === 0 ? null : (
|
||||
<CustomKits kits={widget.data} />
|
||||
);
|
||||
case "sens":
|
||||
return typeof widget.data.motionSens !== "number" &&
|
||||
typeof widget.data.stickSens !== "number" ? null : (
|
||||
@@ -700,6 +711,44 @@ function WeaponPool({
|
||||
);
|
||||
}
|
||||
|
||||
function CustomKits({
|
||||
kits,
|
||||
}: {
|
||||
kits: Extract<LoadedWidget, { id: "custom-kits" }>["data"];
|
||||
}) {
|
||||
const { t } = useTranslation(["weapons"]);
|
||||
|
||||
return (
|
||||
<div className={styles.customKits}>
|
||||
{kits.map((kit, i) => (
|
||||
<div key={i} className={styles.customKit}>
|
||||
<div className={styles.customKitWeapon}>
|
||||
<WeaponImage
|
||||
weaponSplId={kit.weaponSplId}
|
||||
variant="build"
|
||||
size={28}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.customKitName}>
|
||||
{t(`weapons:MAIN_${kit.weaponSplId}`)}
|
||||
</div>
|
||||
<div className={styles.customKitParts}>
|
||||
<div className={styles.customKitPart}>
|
||||
<SubWeaponImage subWeaponId={kit.subWeaponId} size={20} />
|
||||
</div>
|
||||
<div className={styles.customKitPart}>
|
||||
<SpecialWeaponImage
|
||||
specialWeaponId={kit.specialWeaponId}
|
||||
size={20}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function PeakXpWeapon({
|
||||
weaponSplId,
|
||||
peakXp,
|
||||
|
||||
@@ -87,6 +87,8 @@ function WidgetFormFields({ widgetId }: { widgetId: string }) {
|
||||
return <FormField name="weaponSplId" />;
|
||||
case "weapon-pool":
|
||||
return <FormField name="weaponPool" />;
|
||||
case "custom-kits":
|
||||
return <FormField name="kits" />;
|
||||
case "sens":
|
||||
return <SensFields />;
|
||||
case "art":
|
||||
|
||||
@@ -316,6 +316,12 @@ export const WIDGET_LOADERS = {
|
||||
isTenStar: tenStarWeaponSplIds.includes(weapon.id) ? 1 : 0,
|
||||
}));
|
||||
},
|
||||
"custom-kits": async (
|
||||
_userId: number,
|
||||
settings: ExtractWidgetSettings<"custom-kits">,
|
||||
) => {
|
||||
return settings.kits;
|
||||
},
|
||||
"social-links": async (userId: number) => {
|
||||
return UserRepository.findSocialLinksByUserId(userId);
|
||||
},
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
bioMdSchema,
|
||||
bioSchema,
|
||||
countdownSchema,
|
||||
customKitsSchema,
|
||||
favoriteStageSchema,
|
||||
gameBadgesSchema,
|
||||
gameBadgesSmallSchema,
|
||||
@@ -61,6 +62,12 @@ export const ALL_WIDGETS = {
|
||||
schema: weaponPoolWidgetSchema,
|
||||
defaultSettings: { weaponPool: [] },
|
||||
}),
|
||||
defineWidget({
|
||||
id: "custom-kits",
|
||||
slot: "side",
|
||||
schema: customKitsSchema,
|
||||
defaultSettings: { kits: [] },
|
||||
}),
|
||||
defineWidget({ id: "lfg-posts", slot: "main", navItem: "lfg" }),
|
||||
defineWidget({
|
||||
id: "sens",
|
||||
|
||||
@@ -9,10 +9,13 @@ import {
|
||||
badges,
|
||||
customField,
|
||||
datetime,
|
||||
fieldset,
|
||||
numberField,
|
||||
select,
|
||||
selectDynamic,
|
||||
specialWeaponSelect,
|
||||
stageSelect,
|
||||
subWeaponSelect,
|
||||
textArea,
|
||||
textAreaOptional,
|
||||
textField,
|
||||
@@ -104,6 +107,22 @@ export const weaponPoolWidgetSchema = v.object({
|
||||
}),
|
||||
});
|
||||
|
||||
export const customKitsSchema = v.object({
|
||||
kits: array({
|
||||
label: "labels.customKits",
|
||||
max: USER.CUSTOM_KITS_MAX,
|
||||
field: fieldset({
|
||||
fields: v.object({
|
||||
weaponSplId: weaponSelect({ label: "labels.weapon" }),
|
||||
subWeaponId: subWeaponSelect({ label: "labels.subWeapon" }),
|
||||
specialWeaponId: specialWeaponSelect({
|
||||
label: "labels.specialWeapon",
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
const CONTROLLERS = [
|
||||
"s1-pro-con",
|
||||
"s2-pro-con",
|
||||
@@ -220,6 +239,7 @@ const WIDGET_FORM_SCHEMAS: Record<string, FormObjectSchema> = {
|
||||
"peak-xp-unverified": peakXpUnverifiedSchema,
|
||||
"peak-xp-weapon": peakXpWeaponSchema,
|
||||
"weapon-pool": weaponPoolWidgetSchema,
|
||||
"custom-kits": customKitsSchema,
|
||||
sens: sensSchema,
|
||||
art: artSchema,
|
||||
links: linksSchema,
|
||||
|
||||
@@ -215,7 +215,7 @@
|
||||
.widgetSettings {
|
||||
padding: var(--s-3);
|
||||
margin-top: var(--s-1);
|
||||
background-color: var(--color-bg-higher);
|
||||
background-color: var(--color-bg);
|
||||
border-radius: var(--radius-box);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ export const USER = {
|
||||
GAME_BADGES_MAX: 8,
|
||||
GAME_BADGES_SMALL_MAX: 4,
|
||||
WEAPON_POOL_WIDGET_MAX: 7,
|
||||
CUSTOM_KITS_MAX: 3,
|
||||
COUNTDOWN_TITLE_MAX_LENGTH: 50,
|
||||
MARKDOWN_WIDGET_MAX_LENGTH: 2000,
|
||||
TIER_LIST_WIDGET_MAX_LENGTH: 4000,
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import * as React from "react";
|
||||
import type { MainWeaponId, StageId } from "~/modules/in-game-lists/types";
|
||||
import type {
|
||||
MainWeaponId,
|
||||
SpecialWeaponId,
|
||||
StageId,
|
||||
SubWeaponId,
|
||||
} from "~/modules/in-game-lists/types";
|
||||
import type { AnySyncSchema } from "~/utils/schema";
|
||||
import { formRegistry } from "./fields";
|
||||
import { ArrayFormField } from "./fields/ArrayFormField";
|
||||
@@ -16,6 +21,7 @@ import {
|
||||
} from "./fields/InputGroupFormField";
|
||||
import { SelectFormField } from "./fields/SelectFormField";
|
||||
import { StageSelectFormField } from "./fields/StageSelectFormField";
|
||||
import { SubSpecialSelectFormField } from "./fields/SubSpecialSelectFormField";
|
||||
import { SwitchFormField } from "./fields/SwitchFormField";
|
||||
import { TeamSearchFormField } from "./fields/TeamSearchFormField";
|
||||
import { TextareaFormField } from "./fields/TextareaFormField";
|
||||
@@ -596,6 +602,24 @@ export function FormField({
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
formField.type === "sub-weapon-select" ||
|
||||
formField.type === "special-weapon-select"
|
||||
) {
|
||||
return (
|
||||
<SubSpecialSelectFormField
|
||||
{...commonProps}
|
||||
{...formField}
|
||||
weaponType={formField.type === "sub-weapon-select" ? "SUB" : "SPECIAL"}
|
||||
disabled={isDisabled}
|
||||
value={value as SubWeaponId | SpecialWeaponId | null}
|
||||
onChange={
|
||||
handleChange as (v: SubWeaponId | SpecialWeaponId | null) => void
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>Unsupported form field type: {(formField as FormFieldType).type}</div>
|
||||
);
|
||||
|
||||
@@ -5,7 +5,12 @@ import {
|
||||
inGameNameIsValid,
|
||||
normalizeInGameName,
|
||||
} from "~/features/user-page/in-game-name";
|
||||
import type { MainWeaponId, StageId } from "~/modules/in-game-lists/types";
|
||||
import type {
|
||||
MainWeaponId,
|
||||
SpecialWeaponId,
|
||||
StageId,
|
||||
SubWeaponId,
|
||||
} from "~/modules/in-game-lists/types";
|
||||
import { canonicalWeaponSplId } from "~/modules/in-game-lists/weapon-ids";
|
||||
import type { AnySyncSchema, DayMonthYear } from "~/utils/schema";
|
||||
import {
|
||||
@@ -16,7 +21,9 @@ import {
|
||||
preprocess,
|
||||
safeNullableStringSchema,
|
||||
safeStringSchema,
|
||||
specialWeaponId,
|
||||
stageId,
|
||||
subWeaponId,
|
||||
timeString,
|
||||
weaponSplId,
|
||||
} from "~/utils/schema";
|
||||
@@ -993,7 +1000,7 @@ type WeaponSelectArgs = WithTypedTranslationKeys<
|
||||
export function weaponSelect(
|
||||
args: WeaponSelectArgs,
|
||||
): v.GenericSchema<MainWeaponId> {
|
||||
return register(weaponSplId, weaponSelectMetadata(args, true)) as never;
|
||||
return register(weaponSplId, weaponSelectMetadata(args)) as never;
|
||||
}
|
||||
|
||||
export function weaponSelectOptional(
|
||||
@@ -1001,16 +1008,41 @@ export function weaponSelectOptional(
|
||||
): v.OptionalSchema<v.GenericSchema<MainWeaponId>, undefined> {
|
||||
return register(
|
||||
v.optional(weaponSplId),
|
||||
weaponSelectMetadata(args, false),
|
||||
weaponSelectMetadata(args, "weapon-select", false),
|
||||
) as never;
|
||||
}
|
||||
|
||||
function weaponSelectMetadata(args: WeaponSelectArgs, required: boolean) {
|
||||
export function subWeaponSelect(
|
||||
args: WeaponSelectArgs,
|
||||
): v.GenericSchema<SubWeaponId> {
|
||||
return register(
|
||||
subWeaponId,
|
||||
weaponSelectMetadata(args, "sub-weapon-select"),
|
||||
) as never;
|
||||
}
|
||||
|
||||
export function specialWeaponSelect(
|
||||
args: WeaponSelectArgs,
|
||||
): v.GenericSchema<SpecialWeaponId> {
|
||||
return register(
|
||||
specialWeaponId,
|
||||
weaponSelectMetadata(args, "special-weapon-select"),
|
||||
) as never;
|
||||
}
|
||||
|
||||
function weaponSelectMetadata(
|
||||
args: WeaponSelectArgs,
|
||||
type:
|
||||
| "weapon-select"
|
||||
| "sub-weapon-select"
|
||||
| "special-weapon-select" = "weapon-select",
|
||||
required = true,
|
||||
) {
|
||||
return {
|
||||
...args,
|
||||
label: prefixKey(args.label),
|
||||
bottomText: prefixKey(args.bottomText),
|
||||
type: "weapon-select" as const,
|
||||
type,
|
||||
initialValue: null,
|
||||
required,
|
||||
};
|
||||
|
||||
9
app/form/fields/SubSpecialSelectFormField.module.css
Normal file
9
app/form/fields/SubSpecialSelectFormField.module.css
Normal file
@@ -0,0 +1,9 @@
|
||||
.root {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-2);
|
||||
}
|
||||
85
app/form/fields/SubSpecialSelectFormField.tsx
Normal file
85
app/form/fields/SubSpecialSelectFormField.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { SendouSelect, SendouSelectItem } from "~/components/elements/Select";
|
||||
import { Image } from "~/components/Image";
|
||||
import type {
|
||||
SpecialWeaponId,
|
||||
SubWeaponId,
|
||||
} from "~/modules/in-game-lists/types";
|
||||
import {
|
||||
specialWeaponIds,
|
||||
subWeaponIds,
|
||||
} from "~/modules/in-game-lists/weapon-ids";
|
||||
import { specialWeaponImageUrl, subWeaponImageUrl } from "~/utils/urls";
|
||||
import type { FormFieldProps } from "../types";
|
||||
import { FormFieldMessages, useTranslatedTexts } from "./FormFieldWrapper";
|
||||
import styles from "./SubSpecialSelectFormField.module.css";
|
||||
|
||||
type SubSpecialSelectFormFieldProps = FormFieldProps<
|
||||
"sub-weapon-select" | "special-weapon-select"
|
||||
> & {
|
||||
weaponType: "SUB" | "SPECIAL";
|
||||
value: SubWeaponId | SpecialWeaponId | null;
|
||||
onChange: (value: SubWeaponId | SpecialWeaponId | null) => void;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export function SubSpecialSelectFormField({
|
||||
name,
|
||||
label,
|
||||
bottomText,
|
||||
error,
|
||||
required,
|
||||
weaponType,
|
||||
value,
|
||||
onChange,
|
||||
onBlur,
|
||||
disabled,
|
||||
}: SubSpecialSelectFormFieldProps) {
|
||||
const { t } = useTranslation(["weapons"]);
|
||||
const { translatedLabel } = useTranslatedTexts({ label });
|
||||
|
||||
const options: Array<{ id: number; name: string; imgPath: string }> =
|
||||
weaponType === "SUB"
|
||||
? subWeaponIds.map((id) => ({
|
||||
id,
|
||||
name: t(`weapons:SUB_${id}`),
|
||||
imgPath: subWeaponImageUrl(id),
|
||||
}))
|
||||
: specialWeaponIds.map((id) => ({
|
||||
id,
|
||||
name: t(`weapons:SPECIAL_${id}`),
|
||||
imgPath: specialWeaponImageUrl(id),
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<SendouSelect
|
||||
label={translatedLabel}
|
||||
items={options}
|
||||
selectedKey={value}
|
||||
onSelectionChange={(key) => {
|
||||
const newValue = key === null ? null : (Number(key) as SubWeaponId);
|
||||
onChange(newValue);
|
||||
onBlur?.(newValue);
|
||||
}}
|
||||
isRequired={required}
|
||||
clearable={!required}
|
||||
isDisabled={disabled}
|
||||
>
|
||||
{(option) => (
|
||||
<SendouSelectItem
|
||||
key={option.id}
|
||||
id={option.id}
|
||||
textValue={option.name}
|
||||
>
|
||||
<span className={styles.option}>
|
||||
<Image path={option.imgPath} size={24} alt="" />
|
||||
{option.name}
|
||||
</span>
|
||||
</SendouSelectItem>
|
||||
)}
|
||||
</SendouSelect>
|
||||
<FormFieldMessages name={name} error={error} bottomText={bottomText} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -182,6 +182,7 @@ interface FormFieldStageSelect<T extends string> extends FormFieldBase<T> {
|
||||
required: boolean;
|
||||
}
|
||||
|
||||
/** Shared by the main, sub and special weapon selects, which differ only in what they list. */
|
||||
interface FormFieldWeaponSelect<T extends string> extends FormFieldBase<T> {
|
||||
required: boolean;
|
||||
}
|
||||
@@ -213,7 +214,9 @@ export type FormField<V extends string = string> =
|
||||
| FormFieldBadges<"badges">
|
||||
| FormFieldTrophies<"trophies">
|
||||
| FormFieldStageSelect<"stage-select">
|
||||
| FormFieldWeaponSelect<"weapon-select">;
|
||||
| FormFieldWeaponSelect<"weapon-select">
|
||||
| FormFieldWeaponSelect<"sub-weapon-select">
|
||||
| FormFieldWeaponSelect<"special-weapon-select">;
|
||||
|
||||
export type FormFieldProps<T extends FormField["type"]> = Omit<
|
||||
Extract<FormField, { type: T }>,
|
||||
|
||||
8
changelog/2026-09-21-custom-kits-widget.md
Normal file
8
changelog/2026-09-21-custom-kits-widget.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
navItem: u
|
||||
type: feature
|
||||
---
|
||||
New profile widget: Custom Kits
|
||||
|
||||
- Build weapon kits of your own design by mixing any main, sub and special weapon
|
||||
- Show up to 3 of them on your profile
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "",
|
||||
"labels.peakXp": "",
|
||||
"labels.weapon": "",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "",
|
||||
"options.artSource.ALL": "",
|
||||
"options.artSource.MADE-BY": "",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "",
|
||||
"widget.builds": "",
|
||||
"widget.weapon-pool": "",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "",
|
||||
"widget.art": "",
|
||||
"widget.commissions": "",
|
||||
@@ -128,6 +129,7 @@
|
||||
"widgets.description.x-rank-peaks": "",
|
||||
"widgets.description.builds": "",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "",
|
||||
"widgets.description.art": "",
|
||||
"widgets.description.commissions": "",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "",
|
||||
"labels.peakXp": "",
|
||||
"labels.weapon": "",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "",
|
||||
"options.artSource.ALL": "",
|
||||
"options.artSource.MADE-BY": "",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "",
|
||||
"widget.builds": "",
|
||||
"widget.weapon-pool": "",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "",
|
||||
"widget.art": "",
|
||||
"widget.commissions": "",
|
||||
@@ -128,6 +129,7 @@
|
||||
"widgets.description.x-rank-peaks": "",
|
||||
"widgets.description.builds": "",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "",
|
||||
"widgets.description.art": "",
|
||||
"widgets.description.commissions": "",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "Favorite Stage",
|
||||
"labels.peakXp": "Peak XP",
|
||||
"labels.weapon": "Weapon",
|
||||
"labels.customKits": "Kits",
|
||||
"labels.subWeapon": "Sub weapon",
|
||||
"labels.specialWeapon": "Special weapon",
|
||||
"labels.artSource": "Art source",
|
||||
"options.artSource.ALL": "All",
|
||||
"options.artSource.MADE-BY": "Made by me",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "X Rank Peaks Per Mode",
|
||||
"widget.builds": "Builds",
|
||||
"widget.weapon-pool": "Weapon Pool",
|
||||
"widget.custom-kits": "Custom Kits",
|
||||
"widget.sens": "Sensitivity",
|
||||
"widget.art": "Art",
|
||||
"widget.commissions": "Commissions",
|
||||
@@ -128,6 +129,7 @@
|
||||
"widgets.description.x-rank-peaks": "Show your peak X Rank placement for each mode, optionally select division",
|
||||
"widgets.description.builds": "Display your 3 most recent builds",
|
||||
"widgets.description.weapon-pool": "Display your match profile weapon pool or a custom list of weapons",
|
||||
"widgets.description.custom-kits": "Show off weapon kits of your own design",
|
||||
"widgets.description.sens": "Show your sensitivity settings and controller of choice",
|
||||
"widgets.description.art": "Display your 3 most recent art pieces",
|
||||
"widgets.description.commissions": "Show your commission status and details",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "Escenario favorito",
|
||||
"labels.peakXp": "XP máximo",
|
||||
"labels.weapon": "Arma",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "Fuente del arte",
|
||||
"options.artSource.ALL": "Todos",
|
||||
"options.artSource.MADE-BY": "Creado por mí",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "Picos de Rango X por modo",
|
||||
"widget.builds": "Builds",
|
||||
"widget.weapon-pool": "Grupo de armas",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "Sensibilidad",
|
||||
"widget.art": "Arte",
|
||||
"widget.commissions": "Comisiones",
|
||||
@@ -129,6 +130,7 @@
|
||||
"widgets.description.x-rank-peaks": "Muestra tu récord en Rango X de cada modo, con opción de elegir la división",
|
||||
"widgets.description.builds": "Muestra tus 3 builds más recientes",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "Muestra tus ajustes de sensibilidad y el mando que usas",
|
||||
"widgets.description.art": "Muestra tus 3 obras de arte más recientes",
|
||||
"widgets.description.commissions": "Muestra el estado y los detalles de tus comisiones",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "Escenario favorito",
|
||||
"labels.peakXp": "XP máximo",
|
||||
"labels.weapon": "Arma",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "Fuente del arte",
|
||||
"options.artSource.ALL": "Todos",
|
||||
"options.artSource.MADE-BY": "Creado por mí",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "Picos de Rango X por modo",
|
||||
"widget.builds": "Builds",
|
||||
"widget.weapon-pool": "Grupo de armas",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "Sensibilidad",
|
||||
"widget.art": "Arte",
|
||||
"widget.commissions": "Comisiones",
|
||||
@@ -129,6 +130,7 @@
|
||||
"widgets.description.x-rank-peaks": "Muestra tu récord en Rango X de cada modo, con opción de elegir la división",
|
||||
"widgets.description.builds": "Muestra tus 3 builds más recientes",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "Muestra tus ajustes de sensibilidad y el control que usas",
|
||||
"widgets.description.art": "Muestra tus 3 obras de arte más recientes",
|
||||
"widgets.description.commissions": "Muestra el estado y los detalles de tus comisiones",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "",
|
||||
"labels.peakXp": "",
|
||||
"labels.weapon": "",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "",
|
||||
"options.artSource.ALL": "",
|
||||
"options.artSource.MADE-BY": "",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "",
|
||||
"widget.builds": "",
|
||||
"widget.weapon-pool": "",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "",
|
||||
"widget.art": "",
|
||||
"widget.commissions": "",
|
||||
@@ -129,6 +130,7 @@
|
||||
"widgets.description.x-rank-peaks": "",
|
||||
"widgets.description.builds": "",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "",
|
||||
"widgets.description.art": "",
|
||||
"widgets.description.commissions": "",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "",
|
||||
"labels.peakXp": "",
|
||||
"labels.weapon": "",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "",
|
||||
"options.artSource.ALL": "",
|
||||
"options.artSource.MADE-BY": "",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "",
|
||||
"widget.builds": "",
|
||||
"widget.weapon-pool": "",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "",
|
||||
"widget.art": "",
|
||||
"widget.commissions": "",
|
||||
@@ -129,6 +130,7 @@
|
||||
"widgets.description.x-rank-peaks": "",
|
||||
"widgets.description.builds": "",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "",
|
||||
"widgets.description.art": "",
|
||||
"widgets.description.commissions": "",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "",
|
||||
"labels.peakXp": "",
|
||||
"labels.weapon": "",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "",
|
||||
"options.artSource.ALL": "",
|
||||
"options.artSource.MADE-BY": "",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "",
|
||||
"widget.builds": "",
|
||||
"widget.weapon-pool": "",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "",
|
||||
"widget.art": "",
|
||||
"widget.commissions": "",
|
||||
@@ -129,6 +130,7 @@
|
||||
"widgets.description.x-rank-peaks": "",
|
||||
"widgets.description.builds": "",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "",
|
||||
"widgets.description.art": "",
|
||||
"widgets.description.commissions": "",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "",
|
||||
"labels.peakXp": "",
|
||||
"labels.weapon": "",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "",
|
||||
"options.artSource.ALL": "",
|
||||
"options.artSource.MADE-BY": "",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "",
|
||||
"widget.builds": "",
|
||||
"widget.weapon-pool": "",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "",
|
||||
"widget.art": "",
|
||||
"widget.commissions": "",
|
||||
@@ -129,6 +130,7 @@
|
||||
"widgets.description.x-rank-peaks": "",
|
||||
"widgets.description.builds": "",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "",
|
||||
"widgets.description.art": "",
|
||||
"widgets.description.commissions": "",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "",
|
||||
"labels.peakXp": "",
|
||||
"labels.weapon": "",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "",
|
||||
"options.artSource.ALL": "",
|
||||
"options.artSource.MADE-BY": "",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "",
|
||||
"widget.builds": "",
|
||||
"widget.weapon-pool": "",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "",
|
||||
"widget.art": "",
|
||||
"widget.commissions": "",
|
||||
@@ -126,6 +127,7 @@
|
||||
"widgets.description.x-rank-peaks": "",
|
||||
"widgets.description.builds": "",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "",
|
||||
"widgets.description.art": "",
|
||||
"widgets.description.commissions": "",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "",
|
||||
"labels.peakXp": "",
|
||||
"labels.weapon": "",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "",
|
||||
"options.artSource.ALL": "",
|
||||
"options.artSource.MADE-BY": "",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "",
|
||||
"widget.builds": "",
|
||||
"widget.weapon-pool": "",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "",
|
||||
"widget.art": "",
|
||||
"widget.commissions": "",
|
||||
@@ -126,6 +127,7 @@
|
||||
"widgets.description.x-rank-peaks": "",
|
||||
"widgets.description.builds": "",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "",
|
||||
"widgets.description.art": "",
|
||||
"widgets.description.commissions": "",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "",
|
||||
"labels.peakXp": "",
|
||||
"labels.weapon": "",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "",
|
||||
"options.artSource.ALL": "",
|
||||
"options.artSource.MADE-BY": "",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "",
|
||||
"widget.builds": "",
|
||||
"widget.weapon-pool": "",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "",
|
||||
"widget.art": "",
|
||||
"widget.commissions": "",
|
||||
@@ -128,6 +129,7 @@
|
||||
"widgets.description.x-rank-peaks": "",
|
||||
"widgets.description.builds": "",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "",
|
||||
"widgets.description.art": "",
|
||||
"widgets.description.commissions": "",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "",
|
||||
"labels.peakXp": "",
|
||||
"labels.weapon": "",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "",
|
||||
"options.artSource.ALL": "",
|
||||
"options.artSource.MADE-BY": "",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "",
|
||||
"widget.builds": "",
|
||||
"widget.weapon-pool": "",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "",
|
||||
"widget.art": "",
|
||||
"widget.commissions": "",
|
||||
@@ -130,6 +131,7 @@
|
||||
"widgets.description.x-rank-peaks": "",
|
||||
"widgets.description.builds": "",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "",
|
||||
"widgets.description.art": "",
|
||||
"widgets.description.commissions": "",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "",
|
||||
"labels.peakXp": "",
|
||||
"labels.weapon": "",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "",
|
||||
"options.artSource.ALL": "",
|
||||
"options.artSource.MADE-BY": "",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "",
|
||||
"widget.builds": "",
|
||||
"widget.weapon-pool": "",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "",
|
||||
"widget.art": "",
|
||||
"widget.commissions": "",
|
||||
@@ -129,6 +130,7 @@
|
||||
"widgets.description.x-rank-peaks": "",
|
||||
"widgets.description.builds": "",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "",
|
||||
"widgets.description.art": "",
|
||||
"widgets.description.commissions": "",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "",
|
||||
"labels.peakXp": "",
|
||||
"labels.weapon": "",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "",
|
||||
"options.artSource.ALL": "",
|
||||
"options.artSource.MADE-BY": "",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "",
|
||||
"widget.builds": "",
|
||||
"widget.weapon-pool": "",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "",
|
||||
"widget.art": "",
|
||||
"widget.commissions": "",
|
||||
@@ -130,6 +131,7 @@
|
||||
"widgets.description.x-rank-peaks": "",
|
||||
"widgets.description.builds": "",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "",
|
||||
"widgets.description.art": "",
|
||||
"widgets.description.commissions": "",
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
"labels.favoriteStage": "喜爱的场地",
|
||||
"labels.peakXp": "最高 XP",
|
||||
"labels.weapon": "武器",
|
||||
"labels.customKits": "",
|
||||
"labels.subWeapon": "",
|
||||
"labels.specialWeapon": "",
|
||||
"labels.artSource": "作品来源",
|
||||
"options.artSource.ALL": "全部",
|
||||
"options.artSource.MADE-BY": "由我创作",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"widget.x-rank-peaks": "各模式最高X战力",
|
||||
"widget.builds": "配装",
|
||||
"widget.weapon-pool": "武器池",
|
||||
"widget.custom-kits": "",
|
||||
"widget.sens": "灵敏度设置",
|
||||
"widget.art": "插画",
|
||||
"widget.commissions": "约稿",
|
||||
@@ -126,6 +127,7 @@
|
||||
"widgets.description.x-rank-peaks": "展示您各个模式的最高X战力,可自由选择组别",
|
||||
"widgets.description.builds": "展示您最近的 3 套配装",
|
||||
"widgets.description.weapon-pool": "",
|
||||
"widgets.description.custom-kits": "",
|
||||
"widgets.description.sens": "展示您的灵敏度设置和首选控制器",
|
||||
"widgets.description.art": "展示您最近发布的 3 件插画作品",
|
||||
"widgets.description.commissions": "展示您的约稿开放状态与详情",
|
||||
|
||||
Reference in New Issue
Block a user