diff --git a/app/features/user-page/components/Widget.module.css b/app/features/user-page/components/Widget.module.css index 8750d72e0..b4adedffc 100644 --- a/app/features/user-page/components/Widget.module.css +++ b/app/features/user-page/components/Widget.module.css @@ -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)); diff --git a/app/features/user-page/components/Widget.tsx b/app/features/user-page/components/Widget.tsx index ab43ee2d2..79315a022 100644 --- a/app/features/user-page/components/Widget.tsx +++ b/app/features/user-page/components/Widget.tsx @@ -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 : ( ); + case "custom-kits": + return widget.data.length === 0 ? null : ( + + ); 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["data"]; +}) { + const { t } = useTranslation(["weapons"]); + + return ( +
+ {kits.map((kit, i) => ( +
+
+ +
+
+ {t(`weapons:MAIN_${kit.weaponSplId}`)} +
+
+
+ +
+
+ +
+
+
+ ))} +
+ ); +} + function PeakXpWeapon({ weaponSplId, peakXp, diff --git a/app/features/user-page/components/WidgetSettingsForm.tsx b/app/features/user-page/components/WidgetSettingsForm.tsx index 3ecc9aeee..6d7be4ff4 100644 --- a/app/features/user-page/components/WidgetSettingsForm.tsx +++ b/app/features/user-page/components/WidgetSettingsForm.tsx @@ -87,6 +87,8 @@ function WidgetFormFields({ widgetId }: { widgetId: string }) { return ; case "weapon-pool": return ; + case "custom-kits": + return ; case "sens": return ; case "art": diff --git a/app/features/user-page/core/widgets/portfolio-loaders.server.ts b/app/features/user-page/core/widgets/portfolio-loaders.server.ts index e386977dd..b08044747 100644 --- a/app/features/user-page/core/widgets/portfolio-loaders.server.ts +++ b/app/features/user-page/core/widgets/portfolio-loaders.server.ts @@ -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); }, diff --git a/app/features/user-page/core/widgets/portfolio.ts b/app/features/user-page/core/widgets/portfolio.ts index e84a7dfa7..6cec0f4a5 100644 --- a/app/features/user-page/core/widgets/portfolio.ts +++ b/app/features/user-page/core/widgets/portfolio.ts @@ -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", diff --git a/app/features/user-page/core/widgets/widget-form-schemas.ts b/app/features/user-page/core/widgets/widget-form-schemas.ts index 60681189c..f4d79518c 100644 --- a/app/features/user-page/core/widgets/widget-form-schemas.ts +++ b/app/features/user-page/core/widgets/widget-form-schemas.ts @@ -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 = { "peak-xp-unverified": peakXpUnverifiedSchema, "peak-xp-weapon": peakXpWeaponSchema, "weapon-pool": weaponPoolWidgetSchema, + "custom-kits": customKitsSchema, sens: sensSchema, art: artSchema, links: linksSchema, diff --git a/app/features/user-page/routes/u.$identifier.edit-widgets.module.css b/app/features/user-page/routes/u.$identifier.edit-widgets.module.css index 5299195ee..f98c0f53e 100644 --- a/app/features/user-page/routes/u.$identifier.edit-widgets.module.css +++ b/app/features/user-page/routes/u.$identifier.edit-widgets.module.css @@ -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); } diff --git a/app/features/user-page/user-page-constants.ts b/app/features/user-page/user-page-constants.ts index b47b78cb1..1d52f62d8 100644 --- a/app/features/user-page/user-page-constants.ts +++ b/app/features/user-page/user-page-constants.ts @@ -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, diff --git a/app/form/FormField.tsx b/app/form/FormField.tsx index 62469dbd4..b791c8615 100644 --- a/app/form/FormField.tsx +++ b/app/form/FormField.tsx @@ -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 ( + void + } + /> + ); + } + return (
Unsupported form field type: {(formField as FormFieldType).type}
); diff --git a/app/form/fields.ts b/app/form/fields.ts index b172bb11c..c82001579 100644 --- a/app/form/fields.ts +++ b/app/form/fields.ts @@ -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 { - 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, 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 { + return register( + subWeaponId, + weaponSelectMetadata(args, "sub-weapon-select"), + ) as never; +} + +export function specialWeaponSelect( + args: WeaponSelectArgs, +): v.GenericSchema { + 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, }; diff --git a/app/form/fields/SubSpecialSelectFormField.module.css b/app/form/fields/SubSpecialSelectFormField.module.css new file mode 100644 index 000000000..d16f57611 --- /dev/null +++ b/app/form/fields/SubSpecialSelectFormField.module.css @@ -0,0 +1,9 @@ +.root { + width: 100%; +} + +.option { + display: flex; + align-items: center; + gap: var(--s-2); +} diff --git a/app/form/fields/SubSpecialSelectFormField.tsx b/app/form/fields/SubSpecialSelectFormField.tsx new file mode 100644 index 000000000..8263199ed --- /dev/null +++ b/app/form/fields/SubSpecialSelectFormField.tsx @@ -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 ( +
+ { + const newValue = key === null ? null : (Number(key) as SubWeaponId); + onChange(newValue); + onBlur?.(newValue); + }} + isRequired={required} + clearable={!required} + isDisabled={disabled} + > + {(option) => ( + + + + {option.name} + + + )} + + +
+ ); +} diff --git a/app/form/types.ts b/app/form/types.ts index 620cdadad..5596592bb 100644 --- a/app/form/types.ts +++ b/app/form/types.ts @@ -182,6 +182,7 @@ interface FormFieldStageSelect extends FormFieldBase { required: boolean; } +/** Shared by the main, sub and special weapon selects, which differ only in what they list. */ interface FormFieldWeaponSelect extends FormFieldBase { required: boolean; } @@ -213,7 +214,9 @@ export type FormField = | FormFieldBadges<"badges"> | FormFieldTrophies<"trophies"> | FormFieldStageSelect<"stage-select"> - | FormFieldWeaponSelect<"weapon-select">; + | FormFieldWeaponSelect<"weapon-select"> + | FormFieldWeaponSelect<"sub-weapon-select"> + | FormFieldWeaponSelect<"special-weapon-select">; export type FormFieldProps = Omit< Extract, diff --git a/changelog/2026-09-21-custom-kits-widget.md b/changelog/2026-09-21-custom-kits-widget.md new file mode 100644 index 000000000..fe6821d81 --- /dev/null +++ b/changelog/2026-09-21-custom-kits-widget.md @@ -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 diff --git a/locales/da/forms.json b/locales/da/forms.json index 68b46bc07..9e59ab0ab 100644 --- a/locales/da/forms.json +++ b/locales/da/forms.json @@ -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": "", diff --git a/locales/da/user.json b/locales/da/user.json index 23f787c89..10f6eb27c 100644 --- a/locales/da/user.json +++ b/locales/da/user.json @@ -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": "", diff --git a/locales/de/forms.json b/locales/de/forms.json index 3928ef2c5..c631b4a7f 100644 --- a/locales/de/forms.json +++ b/locales/de/forms.json @@ -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": "", diff --git a/locales/de/user.json b/locales/de/user.json index 55cc6fa1a..af6ff25c1 100644 --- a/locales/de/user.json +++ b/locales/de/user.json @@ -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": "", diff --git a/locales/en/forms.json b/locales/en/forms.json index 952febfbe..f6f5f27be 100644 --- a/locales/en/forms.json +++ b/locales/en/forms.json @@ -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", diff --git a/locales/en/user.json b/locales/en/user.json index 236c395d8..6ac82fa4b 100644 --- a/locales/en/user.json +++ b/locales/en/user.json @@ -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", diff --git a/locales/es-ES/forms.json b/locales/es-ES/forms.json index e240d3e23..65aa1e49a 100644 --- a/locales/es-ES/forms.json +++ b/locales/es-ES/forms.json @@ -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í", diff --git a/locales/es-ES/user.json b/locales/es-ES/user.json index a7cdf0655..7aabc581e 100644 --- a/locales/es-ES/user.json +++ b/locales/es-ES/user.json @@ -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", diff --git a/locales/es-US/forms.json b/locales/es-US/forms.json index fbb482be2..3ab9ad9fe 100644 --- a/locales/es-US/forms.json +++ b/locales/es-US/forms.json @@ -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í", diff --git a/locales/es-US/user.json b/locales/es-US/user.json index d9992a1b6..8f5026d6d 100644 --- a/locales/es-US/user.json +++ b/locales/es-US/user.json @@ -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", diff --git a/locales/fr-CA/forms.json b/locales/fr-CA/forms.json index 79a541a22..92240e233 100644 --- a/locales/fr-CA/forms.json +++ b/locales/fr-CA/forms.json @@ -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": "", diff --git a/locales/fr-CA/user.json b/locales/fr-CA/user.json index 4fe0f538d..29263d692 100644 --- a/locales/fr-CA/user.json +++ b/locales/fr-CA/user.json @@ -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": "", diff --git a/locales/fr-EU/forms.json b/locales/fr-EU/forms.json index fcbeb8888..26b5ea4c1 100644 --- a/locales/fr-EU/forms.json +++ b/locales/fr-EU/forms.json @@ -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": "", diff --git a/locales/fr-EU/user.json b/locales/fr-EU/user.json index 93fca72a0..7c541460b 100644 --- a/locales/fr-EU/user.json +++ b/locales/fr-EU/user.json @@ -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": "", diff --git a/locales/he/forms.json b/locales/he/forms.json index a2b7fbbec..4ccb80558 100644 --- a/locales/he/forms.json +++ b/locales/he/forms.json @@ -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": "", diff --git a/locales/he/user.json b/locales/he/user.json index afeab6a77..2a002d212 100644 --- a/locales/he/user.json +++ b/locales/he/user.json @@ -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": "", diff --git a/locales/it/forms.json b/locales/it/forms.json index dd440c1dc..6a4e3091e 100644 --- a/locales/it/forms.json +++ b/locales/it/forms.json @@ -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": "", diff --git a/locales/it/user.json b/locales/it/user.json index 39c0391f4..0d8e3e35b 100644 --- a/locales/it/user.json +++ b/locales/it/user.json @@ -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": "", diff --git a/locales/ja/forms.json b/locales/ja/forms.json index 4c46c89f9..da4f0f1a4 100644 --- a/locales/ja/forms.json +++ b/locales/ja/forms.json @@ -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": "", diff --git a/locales/ja/user.json b/locales/ja/user.json index 74415da32..999725109 100644 --- a/locales/ja/user.json +++ b/locales/ja/user.json @@ -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": "", diff --git a/locales/ko/forms.json b/locales/ko/forms.json index dfe0f85d2..4797a19d8 100644 --- a/locales/ko/forms.json +++ b/locales/ko/forms.json @@ -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": "", diff --git a/locales/ko/user.json b/locales/ko/user.json index e2ba02c02..efbdc34ff 100644 --- a/locales/ko/user.json +++ b/locales/ko/user.json @@ -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": "", diff --git a/locales/nl/forms.json b/locales/nl/forms.json index 28e412623..708e1b018 100644 --- a/locales/nl/forms.json +++ b/locales/nl/forms.json @@ -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": "", diff --git a/locales/nl/user.json b/locales/nl/user.json index 6791a56e4..73f29b767 100644 --- a/locales/nl/user.json +++ b/locales/nl/user.json @@ -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": "", diff --git a/locales/pl/forms.json b/locales/pl/forms.json index e4ae5670a..911201d74 100644 --- a/locales/pl/forms.json +++ b/locales/pl/forms.json @@ -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": "", diff --git a/locales/pl/user.json b/locales/pl/user.json index 419e2514d..de56b625a 100644 --- a/locales/pl/user.json +++ b/locales/pl/user.json @@ -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": "", diff --git a/locales/pt-BR/forms.json b/locales/pt-BR/forms.json index 3bb04395e..a110f7042 100644 --- a/locales/pt-BR/forms.json +++ b/locales/pt-BR/forms.json @@ -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": "", diff --git a/locales/pt-BR/user.json b/locales/pt-BR/user.json index d11c02bc8..9af94f0d0 100644 --- a/locales/pt-BR/user.json +++ b/locales/pt-BR/user.json @@ -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": "", diff --git a/locales/ru/forms.json b/locales/ru/forms.json index 919187487..94de1aa6a 100644 --- a/locales/ru/forms.json +++ b/locales/ru/forms.json @@ -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": "", diff --git a/locales/ru/user.json b/locales/ru/user.json index 33aa60179..2e3f87534 100644 --- a/locales/ru/user.json +++ b/locales/ru/user.json @@ -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": "", diff --git a/locales/zh/forms.json b/locales/zh/forms.json index cd3bacb29..2319084b8 100644 --- a/locales/zh/forms.json +++ b/locales/zh/forms.json @@ -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": "由我创作", diff --git a/locales/zh/user.json b/locales/zh/user.json index b37ed1f42..3390a90e6 100644 --- a/locales/zh/user.json +++ b/locales/zh/user.json @@ -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": "展示您的约稿开放状态与详情",