mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-03-21 18:04:39 -05:00
Bluesky for user & team pages (#1891)
* Migrations * Bluesky for team page * Unify interfaces * For user page * To org social links
This commit is contained in:
parent
803b93e061
commit
59d77642e5
16
app/components/icons/Bsky.tsx
Normal file
16
app/components/icons/Bsky.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
export function BskyIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg
|
||||
className={className}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 568 501"
|
||||
>
|
||||
<title>Bluesky butterfly logo</title>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M123.121 33.664C188.241 82.553 258.281 181.68 284 234.873c25.719-53.192 95.759-152.32 160.879-201.21C491.866-1.611 568-28.906 568 57.947c0 17.346-9.945 145.713-15.778 166.555-20.275 72.453-94.155 90.933-159.875 79.748C507.222 323.8 536.444 388.56 473.333 453.32c-119.86 122.992-172.272-30.859-185.702-70.281-2.462-7.227-3.614-10.608-3.631-7.733-.017-2.875-1.169.506-3.631 7.733-13.43 39.422-65.842 193.273-185.702 70.281-63.111-64.76-33.89-129.52 80.986-149.071-65.72 11.185-139.6-7.295-159.875-79.748C9.945 203.659 0 75.291 0 57.946 0-28.906 76.135-1.612 123.121 33.664Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ export const USER = {
|
|||
CUSTOM_URL_MAX_LENGTH: 32,
|
||||
CUSTOM_NAME_MAX_LENGTH: 32,
|
||||
BATTLEFY_MAX_LENGTH: 32,
|
||||
BSKY_MAX_LENGTH: 50,
|
||||
IN_GAME_NAME_TEXT_MAX_LENGTH: 20,
|
||||
IN_GAME_NAME_DISCRIMINATOR_MAX_LENGTH: 5,
|
||||
WEAPON_POOL_MAX_SIZE: 5,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ export type Generated<T> = T extends ColumnType<infer S, infer I, infer U>
|
|||
? ColumnType<S, I | undefined, U>
|
||||
: ColumnType<T, T | undefined, T>;
|
||||
|
||||
export interface AllTeam {
|
||||
export type MemberRole = (typeof TEAM_MEMBER_ROLES)[number];
|
||||
|
||||
export interface Team {
|
||||
avatarImgId: number | null;
|
||||
bannerImgId: number | null;
|
||||
bio: string | null;
|
||||
|
|
@ -32,11 +34,10 @@ export interface AllTeam {
|
|||
inviteCode: string;
|
||||
name: string;
|
||||
twitter: string | null;
|
||||
bsky: string | null;
|
||||
}
|
||||
|
||||
export type MemberRole = (typeof TEAM_MEMBER_ROLES)[number];
|
||||
|
||||
export interface AllTeamMember {
|
||||
export interface TeamMember {
|
||||
createdAt: Generated<number>;
|
||||
isOwner: Generated<number>;
|
||||
leftAt: number | null;
|
||||
|
|
@ -46,20 +47,6 @@ export interface AllTeamMember {
|
|||
isMainTeam: number;
|
||||
}
|
||||
|
||||
export interface Team {
|
||||
avatarImgId: number | null;
|
||||
bannerImgId: number | null;
|
||||
bio: string | null;
|
||||
createdAt: number | null;
|
||||
css: ColumnType<Record<string, string> | null, string | null, string | null>;
|
||||
customUrl: string;
|
||||
deletedAt: number | null;
|
||||
id: GeneratedAlways<number>;
|
||||
inviteCode: string;
|
||||
name: string;
|
||||
twitter: string | null;
|
||||
}
|
||||
|
||||
export interface Art {
|
||||
authorId: number;
|
||||
createdAt: Generated<number>;
|
||||
|
|
@ -759,6 +746,7 @@ export interface User {
|
|||
stickSens: number | null;
|
||||
twitch: string | null;
|
||||
twitter: string | null;
|
||||
bsky: string | null;
|
||||
battlefy: string | null;
|
||||
vc: Generated<"YES" | "NO" | "LISTEN_ONLY">;
|
||||
youtubeId: string | null;
|
||||
|
|
@ -848,8 +836,8 @@ export type Tables = { [P in keyof DB]: Selectable<DB[P]> };
|
|||
export type TablesInsertable = { [P in keyof DB]: Insertable<DB[P]> };
|
||||
|
||||
export interface DB {
|
||||
AllTeam: AllTeam;
|
||||
AllTeamMember: AllTeamMember;
|
||||
AllTeam: Team;
|
||||
AllTeamMember: TeamMember;
|
||||
Art: Art;
|
||||
ArtTag: ArtTag;
|
||||
ArtUserMetadata: ArtUserMetadata;
|
||||
|
|
@ -887,8 +875,8 @@ export interface DB {
|
|||
SplatoonPlayer: SplatoonPlayer;
|
||||
TaggedArt: TaggedArt;
|
||||
Team: Team;
|
||||
TeamMember: AllTeamMember;
|
||||
TeamMemberWithSecondary: AllTeamMember;
|
||||
TeamMember: TeamMember;
|
||||
TeamMemberWithSecondary: TeamMember;
|
||||
Tournament: Tournament;
|
||||
TournamentStaff: TournamentStaff;
|
||||
TournamentBadgeOwner: TournamentBadgeOwner;
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ export function findByCustomUrl(customUrl: string) {
|
|||
"Team.id",
|
||||
"Team.name",
|
||||
"Team.twitter",
|
||||
"Team.bsky",
|
||||
"Team.bio",
|
||||
"Team.customUrl",
|
||||
"Team.css",
|
||||
|
|
@ -140,6 +141,33 @@ export async function create(
|
|||
});
|
||||
}
|
||||
|
||||
export async function update({
|
||||
id,
|
||||
name,
|
||||
customUrl,
|
||||
bio,
|
||||
twitter,
|
||||
bsky,
|
||||
css,
|
||||
}: Pick<
|
||||
Insertable<Tables["Team"]>,
|
||||
"id" | "name" | "customUrl" | "bio" | "twitter" | "bsky"
|
||||
> & { css: string | null }) {
|
||||
return db
|
||||
.updateTable("AllTeam")
|
||||
.set({
|
||||
name,
|
||||
customUrl,
|
||||
bio,
|
||||
twitter,
|
||||
bsky,
|
||||
css,
|
||||
})
|
||||
.where("id", "=", id)
|
||||
.returningAll()
|
||||
.executeTakeFirstOrThrow();
|
||||
}
|
||||
|
||||
export function switchMainTeam({
|
||||
userId,
|
||||
teamId,
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
import { sql } from "~/db/sql";
|
||||
import type { Team } from "~/db/types";
|
||||
|
||||
const stm = sql.prepare(/*sql*/ `
|
||||
update "AllTeam"
|
||||
set
|
||||
"name" = @name,
|
||||
"customUrl" = @customUrl,
|
||||
"bio" = @bio,
|
||||
"twitter" = @twitter,
|
||||
"css" = @css
|
||||
where "id" = @id
|
||||
returning *
|
||||
`);
|
||||
|
||||
export function edit({
|
||||
id,
|
||||
name,
|
||||
customUrl,
|
||||
bio,
|
||||
twitter,
|
||||
css,
|
||||
}: Pick<Team, "id" | "name" | "customUrl" | "bio" | "twitter" | "css">) {
|
||||
return stm.get({
|
||||
id,
|
||||
name,
|
||||
customUrl,
|
||||
bio,
|
||||
twitter,
|
||||
css,
|
||||
}) as Team;
|
||||
}
|
||||
|
|
@ -37,7 +37,6 @@ import {
|
|||
} from "~/utils/urls";
|
||||
import * as TeamRepository from "../TeamRepository.server";
|
||||
import { deleteTeam } from "../queries/deleteTeam.server";
|
||||
import { edit } from "../queries/edit.server";
|
||||
import { TEAM } from "../team-constants";
|
||||
import { editTeamSchema, teamParamsSchema } from "../team-schemas.server";
|
||||
import { canAddCustomizedColors, isTeamOwner } from "../team-utils";
|
||||
|
|
@ -106,7 +105,7 @@ export const action: ActionFunction = async ({ request, params }) => {
|
|||
};
|
||||
}
|
||||
|
||||
const editedTeam = edit({
|
||||
const editedTeam = await TeamRepository.update({
|
||||
id: team.id,
|
||||
customUrl: newCustomUrl,
|
||||
...data,
|
||||
|
|
@ -158,6 +157,7 @@ export default function EditTeamPage() {
|
|||
) : null}
|
||||
<NameInput />
|
||||
<TwitterInput />
|
||||
<BlueskyInput />
|
||||
<BioTextarea />
|
||||
<SubmitButton
|
||||
className="mt-4"
|
||||
|
|
@ -249,6 +249,26 @@ function TwitterInput() {
|
|||
);
|
||||
}
|
||||
|
||||
function BlueskyInput() {
|
||||
const { t } = useTranslation(["team"]);
|
||||
const { team } = useLoaderData<typeof loader>();
|
||||
const [value, setValue] = React.useState(team.bsky ?? "");
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Label htmlFor="bsky">{t("team:forms.fields.teamBsky")}</Label>
|
||||
<Input
|
||||
leftAddon="https://bsky.app/profile/"
|
||||
id="bsky"
|
||||
name="bsky"
|
||||
maxLength={TEAM.BSKY_MAX_LENGTH}
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function BioTextarea() {
|
||||
const { t } = useTranslation(["team"]);
|
||||
const { team } = useLoaderData<typeof loader>();
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { FormWithConfirm } from "~/components/FormWithConfirm";
|
|||
import { WeaponImage } from "~/components/Image";
|
||||
import { Main } from "~/components/Main";
|
||||
import { SubmitButton } from "~/components/SubmitButton";
|
||||
import { BskyIcon } from "~/components/icons/Bsky";
|
||||
import { EditIcon } from "~/components/icons/Edit";
|
||||
import { StarIcon } from "~/components/icons/Star";
|
||||
import { TwitterIcon } from "~/components/icons/Twitter";
|
||||
|
|
@ -21,6 +22,7 @@ import type { SendouRouteHandle } from "~/utils/remix";
|
|||
import { makeTitle } from "~/utils/strings";
|
||||
import {
|
||||
TEAM_SEARCH_PAGE,
|
||||
bskyUrl,
|
||||
editTeamPage,
|
||||
manageTeamRosterPage,
|
||||
navIconUrl,
|
||||
|
|
@ -126,7 +128,7 @@ function TeamBanner() {
|
|||
})}
|
||||
</div>
|
||||
<div className="team__banner__name">
|
||||
{team.name} <TwitterLink testId="twitter-link" />
|
||||
{team.name} <TwitterLink testId="twitter-link" /> <BskyLink />
|
||||
</div>
|
||||
</div>
|
||||
{team.avatarSrc ? <div className="team__banner__avatar__spacer" /> : null}
|
||||
|
|
@ -151,6 +153,7 @@ function MobileTeamNameCountry() {
|
|||
<div className="team__mobile-team-name">
|
||||
{team.name}
|
||||
<TwitterLink />
|
||||
<BskyLink />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -174,6 +177,23 @@ function TwitterLink({ testId }: { testId?: string }) {
|
|||
);
|
||||
}
|
||||
|
||||
function BskyLink() {
|
||||
const { team } = useLoaderData<typeof loader>();
|
||||
|
||||
if (!team.bsky) return null;
|
||||
|
||||
return (
|
||||
<a
|
||||
className="team__bsky-link"
|
||||
href={bskyUrl(team.bsky)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<BskyIcon />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
function ActionButtons() {
|
||||
const { t } = useTranslation(["team"]);
|
||||
const user = useUser();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ export const TEAM = {
|
|||
NAME_MIN_LENGTH: 2,
|
||||
BIO_MAX_LENGTH: 2000,
|
||||
TWITTER_MAX_LENGTH: 50,
|
||||
BSKY_MAX_LENGTH: 50,
|
||||
MAX_MEMBER_COUNT: 10,
|
||||
MAX_TEAM_COUNT_NON_PATRON: 2,
|
||||
MAX_TEAM_COUNT_PATRON: 5,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ export const editTeamSchema = z.union([
|
|||
falsyToNull,
|
||||
z.string().max(TEAM.TWITTER_MAX_LENGTH).nullable(),
|
||||
),
|
||||
bsky: z.preprocess(
|
||||
falsyToNull,
|
||||
z.string().max(TEAM.BSKY_MAX_LENGTH).nullable(),
|
||||
),
|
||||
css: z.preprocess(falsyToNull, z.string().refine(jsonParseable).nullable()),
|
||||
}),
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -97,6 +97,26 @@
|
|||
fill: #1da1f2;
|
||||
}
|
||||
|
||||
.team__bsky-link {
|
||||
padding: var(--s-1);
|
||||
border: 1px solid;
|
||||
border-radius: 50%;
|
||||
border-color: #1285fe;
|
||||
background-color: #1285fe2f;
|
||||
height: 24.4px;
|
||||
width: 24.4px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.team__bsky-link > svg {
|
||||
width: 0.9rem;
|
||||
}
|
||||
|
||||
.team__bsky-link path {
|
||||
fill: #1285fe;
|
||||
}
|
||||
|
||||
.team__banner__avatar {
|
||||
grid-area: avatar;
|
||||
align-self: flex-end;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import clsx from "clsx";
|
||||
import { BskyIcon } from "~/components/icons/Bsky";
|
||||
import { LinkIcon } from "~/components/icons/Link";
|
||||
import { TwitchIcon } from "~/components/icons/Twitch";
|
||||
import { TwitterIcon } from "~/components/icons/Twitter";
|
||||
|
|
@ -24,6 +25,7 @@ function SocialLink({ url }: { url: string }) {
|
|||
youtube: type === "youtube",
|
||||
twitter: type === "twitter",
|
||||
twitch: type === "twitch",
|
||||
bsky: type === "bsky",
|
||||
})}
|
||||
>
|
||||
<SocialLinkIcon url={url} />
|
||||
|
|
@ -48,6 +50,10 @@ function SocialLinkIcon({ url }: { url: string }) {
|
|||
return <YouTubeIcon />;
|
||||
}
|
||||
|
||||
if (type === "bsky") {
|
||||
return <BskyIcon />;
|
||||
}
|
||||
|
||||
return <LinkIcon />;
|
||||
}
|
||||
|
||||
|
|
@ -64,5 +70,9 @@ const urlToLinkType = (url: string) => {
|
|||
return "youtube";
|
||||
}
|
||||
|
||||
if (url.includes("bsky.app")) {
|
||||
return "bsky";
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -181,3 +181,7 @@
|
|||
.org__social-link__icon-container.twitter svg {
|
||||
fill: #1da1f2;
|
||||
}
|
||||
|
||||
.org__social-link__icon-container.bsky path {
|
||||
fill: #1285fe;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ export async function findProfileByIdentifier(
|
|||
"User.twitter",
|
||||
"User.youtubeId",
|
||||
"User.battlefy",
|
||||
"User.bsky",
|
||||
"User.country",
|
||||
"User.bio",
|
||||
"User.motionSens",
|
||||
|
|
@ -586,6 +587,7 @@ type UpdateProfileArgs = Pick<
|
|||
| "stickSens"
|
||||
| "inGameName"
|
||||
| "battlefy"
|
||||
| "bsky"
|
||||
| "css"
|
||||
| "favoriteBadgeId"
|
||||
| "showDiscordUniqueName"
|
||||
|
|
@ -628,6 +630,7 @@ export function updateProfile(args: UpdateProfileArgs) {
|
|||
inGameName: args.inGameName,
|
||||
css: args.css,
|
||||
battlefy: args.battlefy,
|
||||
bsky: args.bsky,
|
||||
favoriteBadgeId: args.favoriteBadgeId,
|
||||
showDiscordUniqueName: args.showDiscordUniqueName,
|
||||
commissionText: args.commissionText,
|
||||
|
|
|
|||
|
|
@ -91,6 +91,10 @@ const userEditActionSchema = z
|
|||
falsyToNull,
|
||||
z.string().max(USER.BATTLEFY_MAX_LENGTH).nullable(),
|
||||
),
|
||||
bsky: z.preprocess(
|
||||
falsyToNull,
|
||||
z.string().max(USER.BSKY_MAX_LENGTH).nullable(),
|
||||
),
|
||||
stickSens: z.preprocess(
|
||||
processMany(actualNumber, undefinedToNull),
|
||||
z
|
||||
|
|
@ -257,6 +261,7 @@ export default function UserEditPage() {
|
|||
<InGameNameInputs />
|
||||
<SensSelects />
|
||||
<BattlefyInput />
|
||||
<BskyInput />
|
||||
<CountrySelect />
|
||||
<FavBadgeSelect />
|
||||
<WeaponPoolSelect />
|
||||
|
|
@ -455,6 +460,24 @@ function BattlefyInput() {
|
|||
);
|
||||
}
|
||||
|
||||
function BskyInput() {
|
||||
const { t } = useTranslation(["user"]);
|
||||
const data = useLoaderData<typeof loader>();
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<Label htmlFor="bsky">{t("user:bsky")}</Label>
|
||||
<Input
|
||||
name="bsky"
|
||||
id="bsky"
|
||||
maxLength={USER.BSKY_MAX_LENGTH}
|
||||
defaultValue={data.user.bsky ?? undefined}
|
||||
leftAddon="https://bsky.app/profile/"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function WeaponPoolSelect() {
|
||||
const data = useLoaderData<typeof loader>();
|
||||
const [weapons, setWeapons] = React.useState(data.user.weapons);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ import { useTranslation } from "react-i18next";
|
|||
import { Avatar } from "~/components/Avatar";
|
||||
import { Flag } from "~/components/Flag";
|
||||
import { Image, WeaponImage } from "~/components/Image";
|
||||
import { Popover } from "~/components/Popover";
|
||||
import { BattlefyIcon } from "~/components/icons/Battlefy";
|
||||
import { BskyIcon } from "~/components/icons/Bsky";
|
||||
import { DiscordIcon } from "~/components/icons/Discord";
|
||||
import { TwitchIcon } from "~/components/icons/Twitch";
|
||||
import { TwitterIcon } from "~/components/icons/Twitter";
|
||||
|
|
@ -17,6 +19,7 @@ import type { SendouRouteHandle } from "~/utils/remix";
|
|||
import { rawSensToString } from "~/utils/strings";
|
||||
import { assertUnreachable } from "~/utils/types";
|
||||
import {
|
||||
bskyUrl,
|
||||
modeImageUrl,
|
||||
navIconUrl,
|
||||
teamPage,
|
||||
|
|
@ -25,7 +28,6 @@ import {
|
|||
} from "~/utils/urls";
|
||||
import type { UserPageLoaderData } from "./u.$identifier";
|
||||
|
||||
import { Popover } from "~/components/Popover";
|
||||
import { loader } from "../loaders/u.$identifier.index.server";
|
||||
export { loader };
|
||||
|
||||
|
|
@ -67,6 +69,9 @@ export default function UserInfoPage() {
|
|||
{data.user.battlefy ? (
|
||||
<SocialLink type="battlefy" identifier={data.user.battlefy} />
|
||||
) : null}
|
||||
{data.user.bsky ? (
|
||||
<SocialLink type="bsky" identifier={data.user.bsky} />
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<BannedInfo />
|
||||
|
|
@ -168,7 +173,7 @@ function SecondaryTeamsPopover() {
|
|||
}
|
||||
|
||||
interface SocialLinkProps {
|
||||
type: "youtube" | "twitter" | "twitch" | "battlefy";
|
||||
type: "youtube" | "twitter" | "twitch" | "battlefy" | "bsky";
|
||||
identifier: string;
|
||||
}
|
||||
|
||||
|
|
@ -176,7 +181,7 @@ export function SocialLink({
|
|||
type,
|
||||
identifier,
|
||||
}: {
|
||||
type: "youtube" | "twitter" | "twitch" | "battlefy";
|
||||
type: SocialLinkProps["type"];
|
||||
identifier: string;
|
||||
}) {
|
||||
const href = () => {
|
||||
|
|
@ -189,6 +194,8 @@ export function SocialLink({
|
|||
return `https://www.youtube.com/channel/${identifier}`;
|
||||
case "battlefy":
|
||||
return `https://battlefy.com/users/${identifier}`;
|
||||
case "bsky":
|
||||
return bskyUrl(identifier);
|
||||
default:
|
||||
assertUnreachable(type);
|
||||
}
|
||||
|
|
@ -201,6 +208,7 @@ export function SocialLink({
|
|||
twitter: type === "twitter",
|
||||
twitch: type === "twitch",
|
||||
battlefy: type === "battlefy",
|
||||
bsky: type === "bsky",
|
||||
})}
|
||||
href={href()}
|
||||
>
|
||||
|
|
@ -219,6 +227,8 @@ function SocialLinkIcon({ type }: Pick<SocialLinkProps, "type">) {
|
|||
return <YouTubeIcon />;
|
||||
case "battlefy":
|
||||
return <BattlefyIcon />;
|
||||
case "bsky":
|
||||
return <BskyIcon />;
|
||||
default:
|
||||
assertUnreachable(type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,17 @@
|
|||
fill: #de4c5e;
|
||||
}
|
||||
|
||||
.u__social-link.bsky {
|
||||
border-color: #1285fe;
|
||||
background-color: #1285fe2f;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.u__social-link.bsky path {
|
||||
fill: #1285fe;
|
||||
}
|
||||
|
||||
.u__extra-infos {
|
||||
display: flex;
|
||||
max-width: 24rem;
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@ export const SPR_INFO_URL =
|
|||
|
||||
export const twitterUrl = (accountName: string) =>
|
||||
`https://twitter.com/${accountName}`;
|
||||
export const bskyUrl = (accountName: string) =>
|
||||
`https://bsky.app/profile/${accountName}`;
|
||||
export const twitchUrl = (accountName: string) =>
|
||||
`https://twitch.tv/${accountName}`;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
"roles.COACH": "Coach",
|
||||
"roles.CHEERLEADER": "Cheerleader",
|
||||
"forms.fields.teamTwitter": "Team Twitter",
|
||||
"forms.fields.teamBsky": "Team Bluesky",
|
||||
"forms.fields.bio": "Bio",
|
||||
"forms.fields.uploadImages": "Upload images",
|
||||
"forms.fields.uploadImages.pfp": "Profile Picture",
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
"discordExplanation": "Username, profile picture, YouTube, Twitter and Twitch accounts come from your Discord account. See <1>FAQ</1> for more information.",
|
||||
"favoriteBadge": "Favorite Badge",
|
||||
"battlefy": "Battlefy account name",
|
||||
"bsky": "Bluesky account name",
|
||||
|
||||
"forms.showDiscordUniqueName": "Show Discord username",
|
||||
"forms.showDiscordUniqueName.info": "Show your unique Discord name ({{discordUniqueName}}) publicly?",
|
||||
|
|
|
|||
7
migrations/070-bsky.js
Normal file
7
migrations/070-bsky.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
export function up(db) {
|
||||
db.transaction(() => {
|
||||
db.prepare(/* sql */ `alter table "User" add "bsky" text`).run();
|
||||
|
||||
db.prepare(/* sql */ `alter table "AllTeam" add "bsky" text`).run();
|
||||
})();
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user