mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-03-21 18:04:39 -05:00
Bluesky via Discord connection + upgrade remix-auth + remove Twitter references (#2058)
* Remove Twitter references * Upgrade remix auth, bsky via Discord * Test
This commit is contained in:
parent
db10a177a8
commit
32c97a2467
|
|
@ -132,7 +132,7 @@ sendou.ink/
|
|||
│ ├── components/ -- React components
|
||||
│ ├── db/ -- Database layer
|
||||
│ ├── hooks/ -- React hooks
|
||||
│ ├── modules/ -- "nodu_modules but part of the app" https://twitter.com/ryanflorence/status/1535103735952658432
|
||||
│ ├── modules/ -- "node_modules but part of the app"
|
||||
│ ├── routes/ -- Routes see: https://remix.run/docs/en/v1/guides/routing
|
||||
│ ├── styles/ -- All .css files of the project for styling
|
||||
│ ├── utils/ -- Random helper functions used in many places
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import React from "react";
|
||||
import invariant from "~/utils/invariant";
|
||||
|
||||
// TODO: use react aria components
|
||||
|
||||
export function Dialog({
|
||||
children,
|
||||
isOpen,
|
||||
|
|
@ -59,7 +61,6 @@ function useDOMSync(isOpen: boolean) {
|
|||
|
||||
if (isOpen) {
|
||||
dialog.showModal();
|
||||
// TODO: can be replaced with https://twitter.com/argyleink/status/1529869352660439048 once gets control
|
||||
html.classList.add("lock-scroll");
|
||||
} else {
|
||||
dialog.close();
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
export function TwitterIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg
|
||||
className={className}
|
||||
stroke="currentColor"
|
||||
fill="currentColor"
|
||||
strokeWidth="0"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title>Twitter Icon</title>
|
||||
<path d="M16 3.538c-0.588 0.263-1.222 0.438-1.884 0.516 0.678-0.406 1.197-1.050 1.444-1.816-0.634 0.375-1.338 0.65-2.084 0.797-0.6-0.638-1.453-1.034-2.397-1.034-1.813 0-3.281 1.469-3.281 3.281 0 0.256 0.028 0.506 0.084 0.747-2.728-0.138-5.147-1.444-6.766-3.431-0.281 0.484-0.444 1.050-0.444 1.65 0 1.138 0.578 2.144 1.459 2.731-0.538-0.016-1.044-0.166-1.488-0.409 0 0.013 0 0.028 0 0.041 0 1.591 1.131 2.919 2.634 3.219-0.275 0.075-0.566 0.116-0.866 0.116-0.212 0-0.416-0.022-0.619-0.059 0.419 1.303 1.631 2.253 3.066 2.281-1.125 0.881-2.538 1.406-4.078 1.406-0.266 0-0.525-0.016-0.784-0.047 1.456 0.934 3.181 1.475 5.034 1.475 6.037 0 9.341-5.003 9.341-9.341 0-0.144-0.003-0.284-0.009-0.425 0.641-0.459 1.197-1.038 1.637-1.697z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
|
@ -14,7 +14,6 @@ export const USER = {
|
|||
CUSTOM_NAME_MAX_LENGTH: 32,
|
||||
CUSTOM_NAME_REGEXP: notAllEmptyCharactersRegExp,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -245,7 +245,6 @@ async function adminUser() {
|
|||
twitch: "Sendou",
|
||||
youtubeId: "UCWbJLXByvsfQvTcR4HLPs5Q",
|
||||
discordAvatar: ADMIN_TEST_AVATAR,
|
||||
twitter: "sendouc",
|
||||
discordUniqueName: "sendou",
|
||||
});
|
||||
}
|
||||
|
|
@ -294,7 +293,6 @@ function nzapUser() {
|
|||
twitch: null,
|
||||
youtubeId: null,
|
||||
discordAvatar: NZAP_TEST_AVATAR,
|
||||
twitter: null,
|
||||
discordUniqueName: null,
|
||||
});
|
||||
}
|
||||
|
|
@ -474,7 +472,6 @@ function fakeUser(usedNames: Set<string>) {
|
|||
discordId: String(faker.string.numeric(17)),
|
||||
discordName: uniqueDiscordName(usedNames),
|
||||
twitch: null,
|
||||
twitter: null,
|
||||
youtubeId: null,
|
||||
discordUniqueName: null,
|
||||
});
|
||||
|
|
@ -1578,12 +1575,11 @@ function detailedTeam() {
|
|||
sql
|
||||
.prepare(
|
||||
/* sql */ `
|
||||
insert into "AllTeam" ("name", "customUrl", "inviteCode", "twitter", "bio", "avatarImgId", "bannerImgId")
|
||||
insert into "AllTeam" ("name", "customUrl", "inviteCode", "bio", "avatarImgId", "bannerImgId")
|
||||
values (
|
||||
'Alliance Rogue',
|
||||
'alliance-rogue',
|
||||
'${nanoid(INVITE_CODE_LENGTH)}',
|
||||
'AllianceRogueFR',
|
||||
'${faker.lorem.paragraph()}',
|
||||
1,
|
||||
2
|
||||
|
|
@ -1643,13 +1639,12 @@ function otherTeams() {
|
|||
sql
|
||||
.prepare(
|
||||
/* sql */ `
|
||||
insert into "AllTeam" ("id", "name", "customUrl", "inviteCode", "twitter", "bio")
|
||||
insert into "AllTeam" ("id", "name", "customUrl", "inviteCode", "bio")
|
||||
values (
|
||||
@id,
|
||||
@name,
|
||||
@customUrl,
|
||||
@inviteCode,
|
||||
@twitter,
|
||||
@bio
|
||||
)
|
||||
`,
|
||||
|
|
@ -1659,7 +1654,6 @@ function otherTeams() {
|
|||
name: teamName,
|
||||
customUrl: teamCustomUrl,
|
||||
inviteCode: nanoid(INVITE_CODE_LENGTH),
|
||||
twitter: faker.internet.username(),
|
||||
bio: faker.lorem.paragraph(),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ export interface Team {
|
|||
id: GeneratedAlways<number>;
|
||||
inviteCode: string;
|
||||
name: string;
|
||||
twitter: string | null;
|
||||
bsky: string | null;
|
||||
}
|
||||
|
||||
|
|
@ -784,7 +783,6 @@ export interface User {
|
|||
showDiscordUniqueName: Generated<number>;
|
||||
stickSens: number | null;
|
||||
twitch: string | null;
|
||||
twitter: string | null;
|
||||
bsky: string | null;
|
||||
battlefy: string | null;
|
||||
vc: Generated<"YES" | "NO" | "LISTEN_ONLY">;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ export interface User {
|
|||
discordUniqueName: string | null;
|
||||
showDiscordUniqueName: number;
|
||||
twitch: string | null;
|
||||
twitter: string | null;
|
||||
youtubeId: string | null;
|
||||
bio: string | null;
|
||||
css: string | null;
|
||||
|
|
@ -419,7 +418,6 @@ export interface Team {
|
|||
customUrl: string;
|
||||
inviteCode: string;
|
||||
css: string | null;
|
||||
twitter: string | null;
|
||||
bio: string | null;
|
||||
avatarImgId: number | null;
|
||||
bannerImgId: number | null;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
"User.country",
|
||||
"User.discordName",
|
||||
"User.twitch",
|
||||
"User.twitter",
|
||||
"User.battlefy",
|
||||
"User.bsky",
|
||||
"User.customUrl",
|
||||
|
|
@ -95,9 +94,9 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
plusServerTier: user.tier as GetUserResponse["plusServerTier"],
|
||||
socials: {
|
||||
twitch: user.twitch,
|
||||
twitter: user.twitter,
|
||||
battlefy: user.battlefy,
|
||||
bsky: user.bsky,
|
||||
twitter: null, // deprecated field
|
||||
},
|
||||
peakXp:
|
||||
user.xRankPlacements.length > 0
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ export interface GetUserResponse {
|
|||
country: string | null;
|
||||
socials: {
|
||||
twitch: string | null;
|
||||
twitter: string | null;
|
||||
// @deprecated
|
||||
twitter: null;
|
||||
battlefy: string | null;
|
||||
bsky: string | null;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ export const meta: MetaFunction = (args) => {
|
|||
{ property: "og:title", content: data.title },
|
||||
{ name: "description", content: description },
|
||||
{ property: "og:description", content: description },
|
||||
{ name: "twitter:card", content: "summary_large_image" },
|
||||
{ property: "og:image", content: articlePreviewUrl(args.params.slug) },
|
||||
{ property: "og:type", content: "article" },
|
||||
{ property: "og:site_name", content: "sendou.ink" },
|
||||
|
|
|
|||
|
|
@ -1,15 +1,9 @@
|
|||
import type { OAuth2Profile } from "remix-auth-oauth2";
|
||||
import { OAuth2Strategy } from "remix-auth-oauth2";
|
||||
import { z } from "zod";
|
||||
import type { User } from "~/db/types";
|
||||
import * as UserRepository from "~/features/user-page/UserRepository.server";
|
||||
import invariant from "~/utils/invariant";
|
||||
import { logger } from "~/utils/logger";
|
||||
import { DISCORD_AUTH_KEY } from "./authenticator.server";
|
||||
|
||||
interface DiscordExtraParams extends Record<string, string | number> {
|
||||
scope: string;
|
||||
}
|
||||
|
||||
export type LoggedInUser = User["id"];
|
||||
|
||||
|
|
@ -35,88 +29,14 @@ const discordUserDetailsSchema = z.tuple([
|
|||
partialDiscordConnectionsSchema,
|
||||
]);
|
||||
|
||||
export class DiscordStrategy extends OAuth2Strategy<
|
||||
LoggedInUser,
|
||||
OAuth2Profile,
|
||||
DiscordExtraParams
|
||||
> {
|
||||
name = DISCORD_AUTH_KEY;
|
||||
scope: string;
|
||||
export const DiscordStrategy = () => {
|
||||
const envVars = authEnvVars();
|
||||
|
||||
constructor() {
|
||||
const envVars = authEnvVars();
|
||||
|
||||
super(
|
||||
{
|
||||
authorizationURL: "https://discord.com/api/oauth2/authorize",
|
||||
tokenURL:
|
||||
process.env.AUTH_GATEWAY_TOKEN_URL ??
|
||||
"https://discord.com/api/oauth2/token",
|
||||
clientID: envVars.DISCORD_CLIENT_ID,
|
||||
clientSecret: envVars.DISCORD_CLIENT_SECRET,
|
||||
callbackURL: new URL("/auth/callback", envVars.BASE_URL).toString(),
|
||||
},
|
||||
async ({ accessToken }) => {
|
||||
try {
|
||||
const discordResponses = this.authGatewayEnabled()
|
||||
? await this.fetchProfileViaGateway(accessToken)
|
||||
: await this.fetchProfileViaDiscordApi(accessToken);
|
||||
|
||||
const [user, connections] =
|
||||
discordUserDetailsSchema.parse(discordResponses);
|
||||
|
||||
const isAlreadyRegistered = Boolean(
|
||||
await UserRepository.identifierToUserId(user.id),
|
||||
);
|
||||
|
||||
if (!isAlreadyRegistered && !user.verified) {
|
||||
logger.info(`User is not verified with id: ${user.id}`);
|
||||
throw new Error("Unverified user");
|
||||
}
|
||||
|
||||
const userFromDb = await UserRepository.upsert({
|
||||
discordAvatar: user.avatar ?? null,
|
||||
discordId: user.id,
|
||||
discordName: user.global_name ?? user.username,
|
||||
discordUniqueName: user.global_name ? user.username : null,
|
||||
...this.parseConnections(connections),
|
||||
});
|
||||
|
||||
return userFromDb.id;
|
||||
} catch (e) {
|
||||
console.error("Failed to finish authentication:\n", e);
|
||||
throw new Error("Failed to finish authentication");
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
this.scope = "identify connections email";
|
||||
}
|
||||
|
||||
private authGatewayEnabled() {
|
||||
const authGatewayEnabled = () => {
|
||||
return Boolean(process.env.AUTH_GATEWAY_TOKEN_URL);
|
||||
}
|
||||
};
|
||||
|
||||
private async fetchProfileViaDiscordApi(token: string) {
|
||||
const authHeader: [string, string] = ["Authorization", `Bearer ${token}`];
|
||||
|
||||
return Promise.all([
|
||||
fetch("https://discord.com/api/users/@me", {
|
||||
headers: [authHeader],
|
||||
}).then(this.jsonIfOk),
|
||||
fetch("https://discord.com/api/users/@me/connections", {
|
||||
headers: [authHeader],
|
||||
}).then(this.jsonIfOk),
|
||||
]);
|
||||
}
|
||||
|
||||
private async fetchProfileViaGateway(token: string) {
|
||||
const url = `${process.env.AUTH_GATEWAY_PROFILE_URL}?token=${token}`;
|
||||
|
||||
return fetch(url).then(this.jsonIfOk);
|
||||
}
|
||||
|
||||
private jsonIfOk(res: Response) {
|
||||
const jsonIfOk = (res: Response) => {
|
||||
if (!res.ok) {
|
||||
throw new Error(
|
||||
`Auth related call failed with status code ${res.status}`,
|
||||
|
|
@ -124,48 +44,106 @@ export class DiscordStrategy extends OAuth2Strategy<
|
|||
}
|
||||
|
||||
return res.json();
|
||||
}
|
||||
};
|
||||
|
||||
private parseConnections(
|
||||
connections: z.infer<typeof partialDiscordConnectionsSchema>,
|
||||
) {
|
||||
if (!connections) throw new Error("No connections");
|
||||
const fetchProfileViaDiscordApi = (token: string) => {
|
||||
const authHeader: [string, string] = ["Authorization", `Bearer ${token}`];
|
||||
|
||||
const result: {
|
||||
twitch: string | null;
|
||||
twitter: string | null;
|
||||
youtubeId: string | null;
|
||||
} = {
|
||||
twitch: null,
|
||||
twitter: null,
|
||||
youtubeId: null,
|
||||
};
|
||||
return Promise.all([
|
||||
fetch("https://discord.com/api/users/@me", {
|
||||
headers: [authHeader],
|
||||
}).then(jsonIfOk),
|
||||
fetch("https://discord.com/api/users/@me/connections", {
|
||||
headers: [authHeader],
|
||||
}).then(jsonIfOk),
|
||||
]);
|
||||
};
|
||||
|
||||
for (const connection of connections) {
|
||||
if (connection.visibility !== 1 || !connection.verified) continue;
|
||||
const fetchProfileViaGateway = (token: string) => {
|
||||
const url = `${process.env.AUTH_GATEWAY_PROFILE_URL}?token=${token}`;
|
||||
|
||||
switch (connection.type) {
|
||||
case "twitch":
|
||||
result.twitch = connection.name;
|
||||
break;
|
||||
case "twitter":
|
||||
result.twitter = connection.name;
|
||||
break;
|
||||
case "youtube":
|
||||
result.youtubeId = connection.id;
|
||||
return fetch(url).then(jsonIfOk);
|
||||
};
|
||||
|
||||
return new OAuth2Strategy(
|
||||
{
|
||||
clientId: envVars.DISCORD_CLIENT_ID,
|
||||
clientSecret: envVars.DISCORD_CLIENT_SECRET,
|
||||
|
||||
authorizationEndpoint: "https://discord.com/api/oauth2/authorize",
|
||||
tokenEndpoint:
|
||||
process.env.AUTH_GATEWAY_TOKEN_URL ||
|
||||
"https://discord.com/api/oauth2/token",
|
||||
redirectURI: new URL("/auth/callback", envVars.BASE_URL).toString(),
|
||||
|
||||
scopes: ["identify", "connections", "email"],
|
||||
},
|
||||
async ({ tokens }) => {
|
||||
try {
|
||||
const discordResponses = authGatewayEnabled()
|
||||
? await fetchProfileViaGateway(tokens.accessToken())
|
||||
: await fetchProfileViaDiscordApi(tokens.accessToken());
|
||||
|
||||
const [user, connections] =
|
||||
discordUserDetailsSchema.parse(discordResponses);
|
||||
|
||||
const isAlreadyRegistered = Boolean(
|
||||
await UserRepository.identifierToUserId(user.id),
|
||||
);
|
||||
|
||||
if (!isAlreadyRegistered && !user.verified) {
|
||||
logger.info(`User is not verified with id: ${user.id}`);
|
||||
throw new Error("Unverified user");
|
||||
}
|
||||
|
||||
const userFromDb = await UserRepository.upsert({
|
||||
discordAvatar: user.avatar ?? null,
|
||||
discordId: user.id,
|
||||
discordName: user.global_name ?? user.username,
|
||||
discordUniqueName: user.global_name ? user.username : null,
|
||||
...parseConnections(connections),
|
||||
});
|
||||
|
||||
return userFromDb.id;
|
||||
} catch (e) {
|
||||
console.error("Failed to finish authentication:\n", e);
|
||||
throw new Error("Failed to finish authentication");
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
function parseConnections(
|
||||
connections: z.infer<typeof partialDiscordConnectionsSchema>,
|
||||
) {
|
||||
if (!connections) throw new Error("No connections");
|
||||
|
||||
const result: {
|
||||
twitch: string | null;
|
||||
youtubeId: string | null;
|
||||
bsky: string | null;
|
||||
} = {
|
||||
twitch: null,
|
||||
youtubeId: null,
|
||||
bsky: null,
|
||||
};
|
||||
|
||||
for (const connection of connections) {
|
||||
if (connection.visibility !== 1 || !connection.verified) continue;
|
||||
|
||||
switch (connection.type) {
|
||||
case "twitch":
|
||||
result.twitch = connection.name;
|
||||
break;
|
||||
case "youtube":
|
||||
result.youtubeId = connection.id;
|
||||
break;
|
||||
case "bluesky":
|
||||
result.bsky = connection.name;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected authorizationParams() {
|
||||
const urlSearchParams: Record<string, string> = {
|
||||
scope: this.scope,
|
||||
};
|
||||
|
||||
return new URLSearchParams(urlSearchParams);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function authEnvVars() {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,9 @@
|
|||
import { Authenticator } from "remix-auth";
|
||||
import { DiscordStrategy } from "./DiscordStrategy.server";
|
||||
import type { LoggedInUser } from "./DiscordStrategy.server";
|
||||
import { authSessionStorage } from "./session.server";
|
||||
import { DiscordStrategy, type LoggedInUser } from "./DiscordStrategy.server";
|
||||
|
||||
export const DISCORD_AUTH_KEY = "discord";
|
||||
export const SESSION_KEY = "user";
|
||||
export const IMPERSONATED_SESSION_KEY = "impersonated_user";
|
||||
|
||||
export const authenticator = new Authenticator<LoggedInUser>(
|
||||
authSessionStorage,
|
||||
{
|
||||
sessionKey: SESSION_KEY,
|
||||
},
|
||||
);
|
||||
export const authenticator = new Authenticator<LoggedInUser>();
|
||||
|
||||
authenticator.use(new DiscordStrategy());
|
||||
authenticator.use(DiscordStrategy(), "discord");
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ import { isbot } from "isbot";
|
|||
import { z } from "zod";
|
||||
import * as UserRepository from "~/features/user-page/UserRepository.server";
|
||||
import { canAccessLohiEndpoint, canPerformAdminActions } from "~/permissions";
|
||||
import { logger } from "~/utils/logger";
|
||||
import { parseSearchParams, validate } from "~/utils/remix.server";
|
||||
import { ADMIN_PAGE, authErrorUrl } from "~/utils/urls";
|
||||
import { createLogInLink } from "../queries/createLogInLink.server";
|
||||
import { deleteLogInLinkByCode } from "../queries/deleteLogInLinkByCode.server";
|
||||
import { userIdByLogInLinkCode } from "../queries/userIdByLogInLinkCode.server";
|
||||
import {
|
||||
DISCORD_AUTH_KEY,
|
||||
IMPERSONATED_SESSION_KEY,
|
||||
SESSION_KEY,
|
||||
authenticator,
|
||||
|
|
@ -22,23 +22,42 @@ export const callbackLoader: LoaderFunction = async ({ request }) => {
|
|||
const url = new URL(request.url);
|
||||
if (url.searchParams.get("error") === "access_denied") {
|
||||
// The user denied the authentication request
|
||||
// This is part of the oauth2 protocol, but remix-auth-oauth2 doesn't do
|
||||
// nice error handling for this case.
|
||||
// https://www.oauth.com/oauth2-servers/server-side-apps/possible-errors/
|
||||
|
||||
throw redirect(authErrorUrl("aborted"));
|
||||
}
|
||||
|
||||
await authenticator.authenticate(DISCORD_AUTH_KEY, request, {
|
||||
successRedirect: "/",
|
||||
failureRedirect: authErrorUrl("unknown"),
|
||||
});
|
||||
try {
|
||||
const userId = await authenticator.authenticate("discord", request);
|
||||
|
||||
throw new Response("Unknown authentication state", { status: 500 });
|
||||
const session = await authSessionStorage.getSession(
|
||||
request.headers.get(SESSION_KEY),
|
||||
);
|
||||
|
||||
session.set(SESSION_KEY, userId);
|
||||
|
||||
return redirect("/", {
|
||||
headers: {
|
||||
"Set-Cookie": await authSessionStorage.commitSession(session),
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
logger.error("Error during authentication:", error);
|
||||
throw redirect(authErrorUrl("unknown"));
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const logOutAction: ActionFunction = async ({ request }) => {
|
||||
await authenticator.logout(request, { redirectTo: "/" });
|
||||
const session = await authSessionStorage.getSession(
|
||||
request.headers.get(SESSION_KEY),
|
||||
);
|
||||
return redirect("/", {
|
||||
headers: { "Set-Cookie": await authSessionStorage.destroySession(session) },
|
||||
});
|
||||
};
|
||||
|
||||
export const logInAction: ActionFunction = async ({ request }) => {
|
||||
|
|
@ -47,7 +66,7 @@ export const logInAction: ActionFunction = async ({ request }) => {
|
|||
"Login is temporarily disabled",
|
||||
);
|
||||
|
||||
return await authenticator.authenticate(DISCORD_AUTH_KEY, request);
|
||||
return await authenticator.authenticate("discord", request);
|
||||
};
|
||||
|
||||
export const impersonateAction: ActionFunction = async ({ request }) => {
|
||||
|
|
|
|||
|
|
@ -8,15 +8,9 @@ import { languages } from "~/modules/i18n/config";
|
|||
import type { SendouRouteHandle } from "~/utils/remix.server";
|
||||
import { makeTitle } from "~/utils/strings";
|
||||
import {
|
||||
ANTARISKA_TWITTER,
|
||||
BORZOIC_TWITTER,
|
||||
GITHUB_CONTRIBUTORS_URL,
|
||||
LEAN_TWITTER,
|
||||
RHODESMAS_FREESOUND_PROFILE_URL,
|
||||
SENDOU_TWITTER_URL,
|
||||
SPLATOON_3_INK,
|
||||
UBERU_TWITTER,
|
||||
YAGA_TWITTER,
|
||||
} from "~/utils/urls";
|
||||
|
||||
export const meta: MetaFunction = () => {
|
||||
|
|
@ -38,7 +32,7 @@ const PROGRAMMERS = [
|
|||
] as const;
|
||||
|
||||
const TRANSLATORS: Array<{
|
||||
translators: Array<string | { name: string; twitter: string }>;
|
||||
translators: Array<string>;
|
||||
language: (typeof languages)[number]["code"];
|
||||
}> = [
|
||||
{
|
||||
|
|
@ -46,11 +40,7 @@ const TRANSLATORS: Array<{
|
|||
language: "da",
|
||||
},
|
||||
{
|
||||
translators: [
|
||||
{ name: "NoAim™bUrn", twitter: "noaim_brn" },
|
||||
{ name: "Alice", twitter: "Aloschus" },
|
||||
"jgiefer",
|
||||
],
|
||||
translators: ["NoAim™bUrn", "Alice", "jgiefer"],
|
||||
language: "de",
|
||||
},
|
||||
{
|
||||
|
|
@ -74,7 +64,7 @@ const TRANSLATORS: Array<{
|
|||
language: "he",
|
||||
},
|
||||
{
|
||||
translators: [{ name: "funyaaa", twitter: "funyaaa1" }, "taqm", "yutarour"],
|
||||
translators: ["funyaaa", "taqm", "yutarour"],
|
||||
language: "ja",
|
||||
},
|
||||
{
|
||||
|
|
@ -86,15 +76,15 @@ const TRANSLATORS: Array<{
|
|||
language: "pl",
|
||||
},
|
||||
{
|
||||
translators: [{ name: "Ant", twitter: "Ant__Spl" }],
|
||||
translators: ["Ant"],
|
||||
language: "pt-BR",
|
||||
},
|
||||
{
|
||||
translators: [{ name: "Ferrari", twitter: "Blusling" }],
|
||||
translators: ["Ferrari"],
|
||||
language: "nl",
|
||||
},
|
||||
{
|
||||
translators: [{ name: "DoubleCookies", twitter: "DblCookies" }, "yaga"],
|
||||
translators: ["DoubleCookies", "yaga"],
|
||||
language: "ru",
|
||||
},
|
||||
{
|
||||
|
|
@ -111,11 +101,7 @@ export default function ContributionsPage() {
|
|||
<Main>
|
||||
<p>
|
||||
<Trans i18nKey={"contributions:project"} t={t}>
|
||||
Sendou.ink is a project by{" "}
|
||||
<a href={SENDOU_TWITTER_URL} target="_blank" rel="noreferrer">
|
||||
Sendou
|
||||
</a>{" "}
|
||||
with help from contributors:
|
||||
Sendou.ink is a project by Sendou with help from contributors:
|
||||
</Trans>
|
||||
</p>
|
||||
<ul className="mt-2">
|
||||
|
|
@ -125,36 +111,11 @@ export default function ContributionsPage() {
|
|||
{t("contributions:code")}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href={LEAN_TWITTER} target="_blank" rel="noreferrer">
|
||||
Lean
|
||||
</a>{" "}
|
||||
- {t("contributions:lean")}
|
||||
</li>
|
||||
<li>
|
||||
<a href={BORZOIC_TWITTER} target="_blank" rel="noreferrer">
|
||||
borzoic
|
||||
</a>{" "}
|
||||
- {t("contributions:borzoic")}
|
||||
</li>
|
||||
<li>
|
||||
<a href={UBERU_TWITTER} target="_blank" rel="noreferrer">
|
||||
uberu
|
||||
</a>{" "}
|
||||
- {t("contributions:uberu")}
|
||||
</li>
|
||||
<li>
|
||||
<a href={YAGA_TWITTER} target="_blank" rel="noreferrer">
|
||||
yaga
|
||||
</a>{" "}
|
||||
- {t("contributions:yaga")}
|
||||
</li>
|
||||
<li>
|
||||
<a href={ANTARISKA_TWITTER} target="_blank" rel="noreferrer">
|
||||
Antariska, yaga & harryXYZ
|
||||
</a>{" "}
|
||||
- {t("contributions:antariska")}
|
||||
</li>
|
||||
<li>Lean - {t("contributions:lean")}</li>
|
||||
<li>borzoic - {t("contributions:borzoic")}</li>
|
||||
<li>uberu - {t("contributions:uberu")}</li>
|
||||
<li>yaga - {t("contributions:yaga")}</li>
|
||||
<li>Antariska, yaga & harryXYZ - {t("contributions:antariska")}</li>
|
||||
<li>
|
||||
<a href={SPLATOON_3_INK} target="_blank" rel="noreferrer">
|
||||
splatoon3.ink
|
||||
|
|
@ -163,27 +124,12 @@ export default function ContributionsPage() {
|
|||
</li>
|
||||
{TRANSLATORS.map(({ translators, language }) => (
|
||||
<li key={language}>
|
||||
{translators
|
||||
.map((t) =>
|
||||
typeof t === "string" ? (
|
||||
t
|
||||
) : (
|
||||
<a
|
||||
key={t.name}
|
||||
href={`https://twitter.com/${t.twitter}`}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{t.name}
|
||||
</a>
|
||||
),
|
||||
)
|
||||
.map((element, i, arr) => (
|
||||
<React.Fragment key={i}>
|
||||
{element}
|
||||
{i !== arr.length - 1 ? ", " : null}
|
||||
</React.Fragment>
|
||||
))}{" "}
|
||||
{translators.map((element, i, arr) => (
|
||||
<React.Fragment key={i}>
|
||||
{element}
|
||||
{i !== arr.length - 1 ? ", " : null}
|
||||
</React.Fragment>
|
||||
))}{" "}
|
||||
- {t("contributions:translation")} (
|
||||
{languages.find((lang) => lang.code === language)!.name})
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -335,7 +335,6 @@ function SuggestedUser({
|
|||
suggested: { id: suggestion.suggested.id },
|
||||
targetPlusTier: Number(tier),
|
||||
}) ? (
|
||||
// TODO: resetScroll={false} https://twitter.com/ryanflorence/status/1527775882797907969
|
||||
<LinkButton
|
||||
className="plus__comment-button"
|
||||
size="tiny"
|
||||
|
|
|
|||
|
|
@ -392,15 +392,7 @@ function OtherTopics() {
|
|||
less points than they do. This is possible because of “confidence
|
||||
rating” which is an internal value that goes down when you perform as
|
||||
the algorithm expects you to perform and goes up when it's the
|
||||
opposite. Check Joy's{" "}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="https://twitter.com/JoyTheDataNerd/status/1709651029971570960"
|
||||
>
|
||||
Twitter thread
|
||||
</a>{" "}
|
||||
on a longer explanation.
|
||||
opposite.
|
||||
</p>
|
||||
<p>
|
||||
Only the whole set's result matters so points gained/lost are the
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ export default function SendouqRules() {
|
|||
<h2 className="text-lg mt-4">Player eligibility</h2>
|
||||
<div>
|
||||
Players banned by{" "}
|
||||
<a href="https://twitter.com/splatsafety">
|
||||
<a href="https://bsky.app/profile/splatsafety.bsky.social">
|
||||
Splatoon Competitive Community Safety
|
||||
</a>{" "}
|
||||
are not allowed to participate. Playing with banned players is not
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ export function findByCustomUrl(customUrl: string) {
|
|||
.select(({ eb }) => [
|
||||
"Team.id",
|
||||
"Team.name",
|
||||
"Team.twitter",
|
||||
"Team.bsky",
|
||||
"Team.bio",
|
||||
"Team.customUrl",
|
||||
|
|
@ -148,12 +147,11 @@ export async function update({
|
|||
name,
|
||||
customUrl,
|
||||
bio,
|
||||
twitter,
|
||||
bsky,
|
||||
css,
|
||||
}: Pick<
|
||||
Insertable<Tables["Team"]>,
|
||||
"id" | "name" | "customUrl" | "bio" | "twitter" | "bsky"
|
||||
"id" | "name" | "customUrl" | "bio" | "bsky"
|
||||
> & { css: string | null }) {
|
||||
return db
|
||||
.updateTable("AllTeam")
|
||||
|
|
@ -161,7 +159,6 @@ export async function update({
|
|||
name,
|
||||
customUrl,
|
||||
bio,
|
||||
twitter,
|
||||
bsky,
|
||||
css,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ describe("team creation", () => {
|
|||
bio: null,
|
||||
bsky: null,
|
||||
css: null,
|
||||
twitter: null,
|
||||
},
|
||||
{ user: "regular", params: { customUrl: "team-1" } },
|
||||
);
|
||||
|
|
@ -50,7 +49,6 @@ describe("team creation", () => {
|
|||
bio: null,
|
||||
bsky: null,
|
||||
css: null,
|
||||
twitter: null,
|
||||
},
|
||||
{ user: "regular", params: { customUrl: "team-1" } },
|
||||
),
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import {
|
|||
parseRequestPayload,
|
||||
validate,
|
||||
} from "~/utils/remix.server";
|
||||
import { makeTitle, pathnameFromPotentialURL } from "~/utils/strings";
|
||||
import { makeTitle } from "~/utils/strings";
|
||||
import { assertUnreachable } from "~/utils/types";
|
||||
import {
|
||||
TEAM_SEARCH_PAGE,
|
||||
|
|
@ -158,7 +158,6 @@ export default function EditTeamPage() {
|
|||
<CustomizedColorsInput initialColors={css} />
|
||||
) : null}
|
||||
<NameInput />
|
||||
<TwitterInput />
|
||||
<BlueskyInput />
|
||||
<BioTextarea />
|
||||
<SubmitButton
|
||||
|
|
@ -230,27 +229,6 @@ function NameInput() {
|
|||
);
|
||||
}
|
||||
|
||||
function TwitterInput() {
|
||||
const { t } = useTranslation(["team"]);
|
||||
const { team } = useLoaderData<typeof loader>();
|
||||
const [value, setValue] = React.useState(team.twitter ?? "");
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Label htmlFor="twitter">{t("team:forms.fields.teamTwitter")}</Label>
|
||||
<Input
|
||||
leftAddon="https://twitter.com/"
|
||||
id="twitter"
|
||||
name="twitter"
|
||||
maxLength={TEAM.TWITTER_MAX_LENGTH}
|
||||
value={value}
|
||||
onChange={(e) => setValue(pathnameFromPotentialURL(e.target.value))}
|
||||
testId="twitter-input"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function BlueskyInput() {
|
||||
const { t } = useTranslation(["team"]);
|
||||
const { team } = useLoaderData<typeof loader>();
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ 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";
|
||||
import { UsersIcon } from "~/components/icons/Users";
|
||||
import { useUser } from "~/features/auth/core/user";
|
||||
import { isAdmin } from "~/permissions";
|
||||
|
|
@ -27,7 +26,6 @@ import {
|
|||
manageTeamRosterPage,
|
||||
navIconUrl,
|
||||
teamPage,
|
||||
twitterUrl,
|
||||
userPage,
|
||||
userSubmittedImage,
|
||||
} from "~/utils/urls";
|
||||
|
|
@ -128,7 +126,7 @@ function TeamBanner() {
|
|||
})}
|
||||
</div>
|
||||
<div className="team__banner__name">
|
||||
{team.name} <TwitterLink testId="twitter-link" /> <BskyLink />
|
||||
{team.name} <BskyLink />
|
||||
</div>
|
||||
</div>
|
||||
{team.avatarSrc ? <div className="team__banner__avatar__spacer" /> : null}
|
||||
|
|
@ -152,31 +150,12 @@ function MobileTeamNameCountry() {
|
|||
</div>
|
||||
<div className="team__mobile-team-name">
|
||||
{team.name}
|
||||
<TwitterLink />
|
||||
<BskyLink />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TwitterLink({ testId }: { testId?: string }) {
|
||||
const { team } = useLoaderData<typeof loader>();
|
||||
|
||||
if (!team.twitter) return null;
|
||||
|
||||
return (
|
||||
<a
|
||||
className="team__twitter-link"
|
||||
href={twitterUrl(team.twitter)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
data-testid={testId}
|
||||
>
|
||||
<TwitterIcon />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
function BskyLink() {
|
||||
const { team } = useLoaderData<typeof loader>();
|
||||
|
||||
|
|
@ -185,6 +164,7 @@ function BskyLink() {
|
|||
return (
|
||||
<a
|
||||
className="team__bsky-link"
|
||||
data-testid="bsky-link"
|
||||
href={bskyUrl(team.bsky)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ export const TEAM = {
|
|||
NAME_MAX_LENGTH: 64,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -28,10 +28,6 @@ export const editTeamSchema = z.union([
|
|||
falsyToNull,
|
||||
z.string().max(TEAM.BIO_MAX_LENGTH).nullable(),
|
||||
),
|
||||
twitter: z.preprocess(
|
||||
falsyToNull,
|
||||
z.string().max(TEAM.TWITTER_MAX_LENGTH).nullable(),
|
||||
),
|
||||
bsky: z.preprocess(
|
||||
falsyToNull,
|
||||
z.string().max(TEAM.BSKY_MAX_LENGTH).nullable(),
|
||||
|
|
|
|||
|
|
@ -84,19 +84,6 @@
|
|||
gap: var(--s-3);
|
||||
}
|
||||
|
||||
.team__twitter-link {
|
||||
padding: var(--s-1);
|
||||
border: 1px solid;
|
||||
border-radius: 50%;
|
||||
border-color: #1da1f2;
|
||||
background-color: #1da0f22f;
|
||||
}
|
||||
|
||||
.team__twitter-link > svg {
|
||||
width: 0.9rem;
|
||||
fill: #1da1f2;
|
||||
}
|
||||
|
||||
.team__bsky-link {
|
||||
padding: var(--s-1);
|
||||
border: 1px solid;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ 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";
|
||||
import { YouTubeIcon } from "~/components/icons/YouTube";
|
||||
|
||||
export function SocialLinksList({ links }: { links: string[] }) {
|
||||
|
|
@ -23,7 +22,6 @@ function SocialLink({ url }: { url: string }) {
|
|||
<div
|
||||
className={clsx("org__social-link__icon-container", {
|
||||
youtube: type === "youtube",
|
||||
twitter: type === "twitter",
|
||||
twitch: type === "twitch",
|
||||
bsky: type === "bsky",
|
||||
})}
|
||||
|
|
@ -38,10 +36,6 @@ function SocialLink({ url }: { url: string }) {
|
|||
function SocialLinkIcon({ url }: { url: string }) {
|
||||
const type = urlToLinkType(url);
|
||||
|
||||
if (type === "twitter") {
|
||||
return <TwitterIcon />;
|
||||
}
|
||||
|
||||
if (type === "twitch") {
|
||||
return <TwitchIcon />;
|
||||
}
|
||||
|
|
@ -58,10 +52,6 @@ function SocialLinkIcon({ url }: { url: string }) {
|
|||
}
|
||||
|
||||
const urlToLinkType = (url: string) => {
|
||||
if (url.includes("twitter.com") || url.includes("x.com")) {
|
||||
return "twitter";
|
||||
}
|
||||
|
||||
if (url.includes("twitch.tv")) {
|
||||
return "twitch";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,14 +61,6 @@ export const meta: MetaFunction = (args) => {
|
|||
? userSubmittedImage(data.organization.avatarUrl)
|
||||
: undefined,
|
||||
},
|
||||
{
|
||||
name: "twitter:card",
|
||||
content: "summary",
|
||||
},
|
||||
{
|
||||
name: "twitter:title",
|
||||
content: title,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -178,10 +178,6 @@
|
|||
fill: #f00;
|
||||
}
|
||||
|
||||
.org__social-link__icon-container.twitter svg {
|
||||
fill: #1da1f2;
|
||||
}
|
||||
|
||||
.org__social-link__icon-container.bsky path {
|
||||
fill: #1285fe;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,19 +87,6 @@ export const meta: MetaFunction = (args) => {
|
|||
property: "og:image",
|
||||
content: ogImage(),
|
||||
},
|
||||
// Twitter special snowflake tags, see https://developer.x.com/en/docs/twitter-for-websites/cards/overview/summary
|
||||
{
|
||||
name: "twitter:card",
|
||||
content: "summary",
|
||||
},
|
||||
{
|
||||
name: "twitter:title",
|
||||
content: title,
|
||||
},
|
||||
{
|
||||
name: "twitter:site",
|
||||
content: "@sendouink",
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -137,7 +137,6 @@ export async function findProfileByIdentifier(
|
|||
.leftJoin("PlusTier", "PlusTier.userId", "User.id")
|
||||
.select(({ eb }) => [
|
||||
"User.twitch",
|
||||
"User.twitter",
|
||||
"User.youtubeId",
|
||||
"User.battlefy",
|
||||
"User.bsky",
|
||||
|
|
@ -461,7 +460,6 @@ export async function search({
|
|||
eb("User.username", "like", query),
|
||||
eb("User.inGameName", "like", query),
|
||||
eb("User.discordUniqueName", "like", query),
|
||||
eb("User.twitter", "like", query),
|
||||
eb("User.customUrl", "like", query),
|
||||
]),
|
||||
)
|
||||
|
|
@ -490,7 +488,6 @@ export async function search({
|
|||
eb("User.username", "like", fuzzyQuery),
|
||||
eb("User.inGameName", "like", fuzzyQuery),
|
||||
eb("User.discordUniqueName", "like", fuzzyQuery),
|
||||
eb("User.twitter", "like", fuzzyQuery),
|
||||
])
|
||||
.and(
|
||||
"User.id",
|
||||
|
|
@ -575,8 +572,8 @@ export function upsert(
|
|||
| "discordAvatar"
|
||||
| "discordUniqueName"
|
||||
| "twitch"
|
||||
| "twitter"
|
||||
| "youtubeId"
|
||||
| "bsky"
|
||||
>,
|
||||
) {
|
||||
return db
|
||||
|
|
@ -601,7 +598,6 @@ type UpdateProfileArgs = Pick<
|
|||
| "stickSens"
|
||||
| "inGameName"
|
||||
| "battlefy"
|
||||
| "bsky"
|
||||
| "css"
|
||||
| "favoriteBadgeId"
|
||||
| "showDiscordUniqueName"
|
||||
|
|
@ -644,7 +640,6 @@ 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,
|
||||
|
|
|
|||
|
|
@ -99,10 +99,6 @@ 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
|
||||
|
|
@ -269,7 +265,6 @@ export default function UserEditPage() {
|
|||
<InGameNameInputs />
|
||||
<SensSelects />
|
||||
<BattlefyInput />
|
||||
<BskyInput />
|
||||
<CountrySelect />
|
||||
<FavBadgeSelect />
|
||||
<WeaponPoolSelect />
|
||||
|
|
@ -292,7 +287,7 @@ export default function UserEditPage() {
|
|||
)}
|
||||
<FormMessage type="info">
|
||||
<Trans i18nKey={"user:discordExplanation"} t={t}>
|
||||
Username, profile picture, YouTube, Twitter and Twitch accounts come
|
||||
Username, profile picture, YouTube, Bluesky and Twitch accounts come
|
||||
from your Discord account. See <Link to={FAQ_PAGE}>FAQ</Link> for
|
||||
more information.
|
||||
</Trans>
|
||||
|
|
@ -469,24 +464,6 @@ 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);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ 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";
|
||||
import { YouTubeIcon } from "~/components/icons/YouTube";
|
||||
import { BadgeDisplay } from "~/features/badges/components/BadgeDisplay";
|
||||
import { modesShort } from "~/modules/in-game-lists";
|
||||
|
|
@ -60,9 +59,6 @@ export default function UserInfoPage() {
|
|||
{data.user.twitch ? (
|
||||
<SocialLink type="twitch" identifier={data.user.twitch} />
|
||||
) : null}
|
||||
{data.user.twitter ? (
|
||||
<SocialLink type="twitter" identifier={data.user.twitter} />
|
||||
) : null}
|
||||
{data.user.youtubeId ? (
|
||||
<SocialLink type="youtube" identifier={data.user.youtubeId} />
|
||||
) : null}
|
||||
|
|
@ -173,7 +169,7 @@ function SecondaryTeamsPopover() {
|
|||
}
|
||||
|
||||
interface SocialLinkProps {
|
||||
type: "youtube" | "twitter" | "twitch" | "battlefy" | "bsky";
|
||||
type: "youtube" | "twitch" | "battlefy" | "bsky";
|
||||
identifier: string;
|
||||
}
|
||||
|
||||
|
|
@ -188,8 +184,6 @@ export function SocialLink({
|
|||
switch (type) {
|
||||
case "twitch":
|
||||
return `https://www.twitch.tv/${identifier}`;
|
||||
case "twitter":
|
||||
return `https://www.twitter.com/${identifier}`;
|
||||
case "youtube":
|
||||
return `https://www.youtube.com/channel/${identifier}`;
|
||||
case "battlefy":
|
||||
|
|
@ -205,7 +199,6 @@ export function SocialLink({
|
|||
<a
|
||||
className={clsx("u__social-link", {
|
||||
youtube: type === "youtube",
|
||||
twitter: type === "twitter",
|
||||
twitch: type === "twitch",
|
||||
battlefy: type === "battlefy",
|
||||
bsky: type === "bsky",
|
||||
|
|
@ -221,8 +214,6 @@ function SocialLinkIcon({ type }: Pick<SocialLinkProps, "type">) {
|
|||
switch (type) {
|
||||
case "twitch":
|
||||
return <TwitchIcon />;
|
||||
case "twitter":
|
||||
return <TwitterIcon />;
|
||||
case "youtube":
|
||||
return <YouTubeIcon />;
|
||||
case "battlefy":
|
||||
|
|
|
|||
|
|
@ -70,15 +70,6 @@
|
|||
fill: #f00;
|
||||
}
|
||||
|
||||
.u__social-link.twitter {
|
||||
border-color: #1da1f2;
|
||||
background-color: #1da0f22f;
|
||||
}
|
||||
|
||||
.u__social-link.twitter > svg {
|
||||
fill: #1da1f2;
|
||||
}
|
||||
|
||||
.u__social-link.twitch {
|
||||
border-color: #9146ff;
|
||||
background-color: #9146ff2f;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { pathnameFromPotentialURL } from "./strings";
|
|||
|
||||
describe("pathnameFromPotentialURL()", () => {
|
||||
test("Resolves path name from valid URL", () => {
|
||||
expect(pathnameFromPotentialURL("https://twitter.com/sendouc")).toBe(
|
||||
expect(pathnameFromPotentialURL("https://bsky.app/sendouc")).toBe(
|
||||
"sendouc",
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ export const conditionalUserSubmittedImage = (fileName: string) =>
|
|||
|
||||
export const PLUS_SERVER_DISCORD_URL = "https://discord.gg/FW4dKrY";
|
||||
export const SENDOU_INK_DISCORD_URL = "https://discord.gg/sendou";
|
||||
export const SENDOU_TWITTER_URL = "https://twitter.com/sendouc";
|
||||
export const SENDOU_INK_PATREON_URL = "https://patreon.com/sendou";
|
||||
export const NINTENDO_COMMUNITY_TOURNAMENTS_GUIDELINES_URL =
|
||||
"https://en-americas-support.nintendo.com/app/answers/detail/a_id/63454";
|
||||
|
|
@ -76,11 +75,6 @@ export const PATREON_HOW_TO_CONNECT_DISCORD_URL =
|
|||
export const SENDOU_INK_GITHUB_URL = "https://github.com/Sendouc/sendou.ink";
|
||||
export const GITHUB_CONTRIBUTORS_URL =
|
||||
"https://github.com/Sendouc/sendou.ink/graphs/contributors";
|
||||
export const BORZOIC_TWITTER = "https://twitter.com/borzoic_";
|
||||
export const LEAN_TWITTER = "https://twitter.com/LeanYoshi";
|
||||
export const UBERU_TWITTER = "https://twitter.com/uberu5";
|
||||
export const YAGA_TWITTER = "https://twitter.com/a_bog_hag";
|
||||
export const ANTARISKA_TWITTER = "https://twitter.com/antariska_spl";
|
||||
export const ipLabsMaps = (pool: string) =>
|
||||
`https://maps.iplabs.ink/?3&pool=${pool}`;
|
||||
export const SPLATOON_3_INK = "https://splatoon3.ink/";
|
||||
|
|
@ -89,8 +83,6 @@ export const RHODESMAS_FREESOUND_PROFILE_URL =
|
|||
export const SPR_INFO_URL =
|
||||
"https://www.pgstats.com/articles/introducing-spr-and-uf";
|
||||
|
||||
export const twitterUrl = (accountName: string) =>
|
||||
`https://twitter.com/${accountName}`;
|
||||
export const bskyUrl = (accountName: string) =>
|
||||
`https://bsky.app/profile/${accountName}`;
|
||||
export const twitchUrl = (accountName: string) =>
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ test.describe("Team page", () => {
|
|||
await page.getByTestId("name-input").clear();
|
||||
await page.getByTestId("name-input").fill("Better Alliance Rogue");
|
||||
|
||||
await page.getByTestId("twitter-input").clear();
|
||||
await page.getByTestId("twitter-input").fill("BetterAllianceRogue");
|
||||
await page.getByLabel("Team Bluesky").clear();
|
||||
await page.getByLabel("Team Bluesky").fill("BetterAllianceRogue");
|
||||
|
||||
await page.getByTestId("bio-textarea").clear();
|
||||
await page.getByTestId("bio-textarea").fill("shorter bio");
|
||||
|
|
@ -68,9 +68,9 @@ test.describe("Team page", () => {
|
|||
|
||||
await expect(page).toHaveURL(/better-alliance-rogue/);
|
||||
await page.getByText("shorter bio").isVisible();
|
||||
await expect(page.getByTestId("twitter-link")).toHaveAttribute(
|
||||
await expect(page.getByTestId("bsky-link").first()).toHaveAttribute(
|
||||
"href",
|
||||
"https://twitter.com/BetterAllianceRogue",
|
||||
"https://bsky.app/profile/BetterAllianceRogue",
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"q5": "Findes der en sendou.ink app?",
|
||||
"a5": "Nej, men man kan installere Sendou ink som en ”Progressive Web App”, som fungerer som en traditionel app. Hvor man understøttelse af fuld skærm, skrivebordsikon og kører som en proces separat fra en webbrowser. Google ”How to install pwa on *din browser’ for at sfinde en vejledning til at gøre dette.",
|
||||
|
||||
"q6": "Hvordan tilføjer man en Twitch/Twitter/YouTube-profil til min sendou.ink-profil?",
|
||||
"q6": "Hvordan tilføjer man en Twitch/Bluesky/YouTube-profil til min sendou.ink-profil?",
|
||||
"a6": "Vi bruger Discord til dette formål. Tilknyt profilerne til Discord og verificér dem. Log derefter af og på sendou.ink for at få tilknyttet dine profiler på sendou.ink. ",
|
||||
|
||||
"q7": "Hvordan kan jeg uploade videoer?",
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
"roles.FLEX": "Fleksibel",
|
||||
"roles.SUB": "Vikar",
|
||||
"roles.COACH": "Træner",
|
||||
"forms.fields.teamTwitter": "Holdets Twitter",
|
||||
"forms.fields.bio": "Bio",
|
||||
"forms.fields.uploadImages": "Upload billeder",
|
||||
"forms.fields.uploadImages.pfp": "Profilbillede",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"stick": "Styrepind",
|
||||
"sens": "Følsomhed",
|
||||
"weaponPool": "Våbenpulje",
|
||||
"discordExplanation": "Brugernavn, Profilbillede, Youtube-, Twitter- og Twitch-konter er hentet via din Discord-konto. Se <1>FAQ</1> for yderligere information.",
|
||||
"discordExplanation": "Brugernavn, Profilbillede, Youtube-, Bluesky- og Twitch-konter er hentet via din Discord-konto. Se <1>FAQ</1> for yderligere information.",
|
||||
"favoriteBadge": "Yndlingsmærke",
|
||||
"battlefy": "Battlefy brugernavn",
|
||||
|
||||
|
|
@ -42,7 +42,6 @@
|
|||
"forms.info.favoriteBadge": "Dit yndlingsmærke bliver som standard vist i stor størrelse på din profil",
|
||||
"forms.info.battlefy": "Battlefy-brugernavn bruges til seeding og bekræftelse i nogle turneringer",
|
||||
|
||||
"search.info": "Søg efter brugere ved hjælp af deres Discord-, Splatoon 3- eller Twitter-navn",
|
||||
"search.noResults": "Søgningen ’{{query}}’ fandt ingen brugere",
|
||||
|
||||
"seasons": "Sæsoner",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,6 @@
|
|||
"q5": "Gibt es eine sendou.ink App?",
|
||||
"a5": "Nein, aber sendou.ink kann als 'Progressive Web App' installiert werden. Dies bietet viele der Vorteile einer App, wie Vollbildmodus, Icon auf dem Homebildschirm oder separater Browser-Prozess. Google nach 'wie pwa auf *deinem browser* installieren' für eine Anleitung.",
|
||||
|
||||
"q6": "Wie füge ich Twitch/Twitter/YouTube zu meinem Profil hinzu?",
|
||||
"q6": "Wie füge ich Twitch/Bluesky/YouTube zu meinem Profil hinzu?",
|
||||
"a6": "Dafür wird dein Discord-Profil verwendet. Verknüpfe und verifiziere deine Profile auf Discord und logge dich dann auf sendou.ink aus und wieder ein, um sie zu aktualisieren."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
"roles.MIDLINE": "Midline",
|
||||
"roles.BACKLINE": "Backline",
|
||||
"roles.COACH": "Coach",
|
||||
"forms.fields.teamTwitter": "Team-Twitter",
|
||||
"forms.fields.bio": "Bio",
|
||||
"forms.fields.uploadImages": "Bilder hochladen",
|
||||
"forms.fields.uploadImages.pfp": "Profilbild",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
"stick": "Stick",
|
||||
"sens": "Empfindlichkeit",
|
||||
"weaponPool": "Waffenpool",
|
||||
"discordExplanation": "Der Username, Profilbild, YouTube-, Twitter- und Twitch-Konten stammen von deinem Discord-Konto. Mehr Infos in den <1>FAQ</1>.",
|
||||
"discordExplanation": "Der Username, Profilbild, YouTube-, Bluesky- und Twitch-Konten stammen von deinem Discord-Konto. Mehr Infos in den <1>FAQ</1>.",
|
||||
|
||||
"results.placing": "Platzierung",
|
||||
"results.team": "Team",
|
||||
|
|
@ -27,6 +27,5 @@
|
|||
"forms.errors.invalidCustomUrl.duplicate": "Diese Benutzerdefinierte URL wird bereits verwendet",
|
||||
"forms.errors.invalidSens": "Empfindlichkeit der Bewegungssteuerung kann nur festgelegt werden, wenn Empfindlichkeit R-Stick festgelegt ist",
|
||||
|
||||
"search.info": "Suche nach Nutzern anhand des Discord-, Splatoon-3- oder Twitter-Namens",
|
||||
"search.noResults": "Keine Nutzer gefunden, die '{{query}}' entsprechen"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
"auth.errors.aborted": "Login Aborted",
|
||||
"auth.errors.failed": "Login Failed",
|
||||
"auth.errors.discordPermissions": "For your sendou.ink profile, the site needs access to your Discord profile's name, avatar and social connections.",
|
||||
"auth.errors.unknown": "Does your Discord account have a verified email? For help please reach out to us via the #helpdesk channel on our Discord:",
|
||||
"auth.errors.unknown": "Unknown error, try again a bit later. Verify also that your Discord account has a verified email. For help please reach out to us via the #helpdesk channel on our Discord:",
|
||||
|
||||
"footer.github.subtitle": "Source code",
|
||||
"footer.discord.subtitle": "Help & feedback",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
"q5": "Is there a sendou.ink app?",
|
||||
"a5": "No, but sendou.ink can be installed as a 'Progressive Web App' that gets many of the same benefits such as full-screen, an icon on the home screen and a separate process from the browser. Google 'how to install PWA on *your browser*' to see how.",
|
||||
|
||||
"q6": "How to add Twitch/Twitter/YouTube to my profile?",
|
||||
"q6": "How to add Twitch/Bluesky/YouTube to my profile?",
|
||||
"a6": "We use your Discord profile for that. Connect and verify them on Discord then log out and back in on sendou.ink to have them update.",
|
||||
|
||||
"q7": "How can I add videos?",
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
"roles.SUB": "Sub",
|
||||
"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",
|
||||
|
|
|
|||
|
|
@ -11,10 +11,9 @@
|
|||
"stick": "Stick",
|
||||
"sens": "Sens",
|
||||
"weaponPool": "Weapon pool",
|
||||
"discordExplanation": "Username, profile picture, YouTube, Twitter and Twitch accounts come from your Discord account. See <1>FAQ</1> for more information.",
|
||||
"discordExplanation": "Username, profile picture, YouTube, Bluesky 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?",
|
||||
|
|
@ -44,7 +43,7 @@
|
|||
"forms.info.favoriteBadge": "Your favorite badge is shown as big by default on your profile.",
|
||||
"forms.info.battlefy": "Battlefy account name is used for seeding and verification in some tournaments",
|
||||
|
||||
"search.info": "Search for users by Discord, Splatoon 3 or Twitter name",
|
||||
"search.info": "Search for users by Discord or Splatoon 3 name",
|
||||
"search.noResults": "No users found matching '{{query}}'",
|
||||
|
||||
"seasons": "Seasons",
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@
|
|||
"auth.errors.aborted": "Ingreso cancelado",
|
||||
"auth.errors.failed": "Ingreso fallido",
|
||||
"auth.errors.discordPermissions": "Para tu perfil en sendou.ink, el sitio requiere aceso a tu nombre en Discord, avatar, y redes sociales.",
|
||||
"auth.errors.unknown": "Ingreso fallido debido a un error de servidor. Por favor intenta más tarde o usa /login a travez de Lohi bot. Se puede encontrar en el Discord de sendou.ink:",
|
||||
|
||||
"footer.github.subtitle": "Código fuente",
|
||||
"footer.discord.subtitle": "Ayuda y comentarios",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"q5": "¿Hay un app de sendou.ink?",
|
||||
"a5": "No, pero sendou.ink se puede instalar como una 'aplicación web progresiva' (PWA) que obtiene muchos de los mismos beneficios, como pantalla completa, un ícono en la pantalla de inicio y un proceso separado. Busque en Google 'cómo instalar PWA en *su navegador*' para encontrar instrucciones.",
|
||||
|
||||
"q6": "¿Cómo puedo agregar Twitch/Twitter/YouTube a mi perfil?",
|
||||
"q6": "¿Cómo puedo agregar Twitch/Bluesky/YouTube a mi perfil?",
|
||||
"a6": "Usamos tu perfil de Discord para eso. Conéctalos y verifícalos a travéz de Discord. Luego, cierra tu sesión y vuelve a iniciar tu sesión en sendou.ink para actualizar.",
|
||||
|
||||
"q7": "¿Cómo puedo agregar videos?",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
"roles.BACKLINE": "Defensor",
|
||||
"roles.FLEX": "Flex",
|
||||
"roles.COACH": "Entrenador",
|
||||
"forms.fields.teamTwitter": "Twitter del equipo",
|
||||
"forms.fields.bio": "Bio",
|
||||
"forms.fields.uploadImages": "Subir imágenes",
|
||||
"forms.fields.uploadImages.pfp": "Imagen de perfil",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
"stick": "Palanca",
|
||||
"sens": "Sens",
|
||||
"weaponPool": "Grupo de armas",
|
||||
"discordExplanation": "Tu nombre, foto, y cuentas de YouTube, Twitter y Twitch se obtienen por tu cuenta en Discord. Ver <1>FAQ</1> para más información.",
|
||||
"discordExplanation": "Tu nombre, foto, y cuentas de YouTube, Bluesky y Twitch se obtienen por tu cuenta en Discord. Ver <1>FAQ</1> para más información.",
|
||||
"favoriteBadge": "Insignia favorita",
|
||||
|
||||
"forms.showDiscordUniqueName": "Mostrar usuario de Discord",
|
||||
|
|
@ -35,7 +35,6 @@
|
|||
"forms.errors.invalidSens": "Motion sens can't be set if R-stick sens isn't",
|
||||
"forms.info.favoriteBadge": "Tu insignia favorita se muestra en forma grande en tu perfil.",
|
||||
|
||||
"search.info": "Buscar usuarios usando su nombre en Discord, Splatoon 3 o Twitter",
|
||||
"search.noResults": "No se encontraron usuarios que coincidan con '{{query}}'",
|
||||
|
||||
"seasons": "Temporadas",
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
"auth.errors.aborted": "Ingreso cancelado",
|
||||
"auth.errors.failed": "Ingreso fallido",
|
||||
"auth.errors.discordPermissions": "Para tu perfil en sendou.ink, el sitio requiere aceso a tu nombre en Discord, avatar, y redes sociales.",
|
||||
"auth.errors.unknown": "Ingreso fallido debido a un error de servidor. Por favor intenta más tarde o usa /login a travez de Lohi bot. Se puede encontrar en el Discord de sendou.ink:",
|
||||
|
||||
"footer.github.subtitle": "Código fuente",
|
||||
"footer.discord.subtitle": "Ayuda y comentarios",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"q5": "¿Hay un app de sendou.ink?",
|
||||
"a5": "No, pero sendou.ink se puede instalar como una 'aplicación web progresiva' (PWA) que obtiene muchos de los mismos beneficios, como pantalla completa, un ícono en la pantalla de inicio y un proceso separado. Busque en Google 'cómo instalar PWA en *su navegador*' para encontrar instrucciones.",
|
||||
|
||||
"q6": "¿Cómo puedo agregar Twitch/Twitter/YouTube a mi perfil?",
|
||||
"q6": "¿Cómo puedo agregar Twitch/Bluesky/YouTube a mi perfil?",
|
||||
"a6": "Usamos tu perfil de Discord para eso. Conéctalos y verifícalos a travéz de Discord. Luego, cierra tu sesión y vuelve a iniciar tu sesión en sendou.ink para actualizar.",
|
||||
|
||||
"q7": "¿Cómo puedo agregar videos?",
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
"roles.FLEX": "Flex",
|
||||
"roles.SUB": "Suplente",
|
||||
"roles.COACH": "Entrenador",
|
||||
"forms.fields.teamTwitter": "Twitter del equipo",
|
||||
"forms.fields.bio": "Bio",
|
||||
"forms.fields.uploadImages": "Subir imágenes",
|
||||
"forms.fields.uploadImages.pfp": "Imagen de perfil",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"stick": "Palanca",
|
||||
"sens": "Sens",
|
||||
"weaponPool": "Grupo de armas",
|
||||
"discordExplanation": "Tu nombre, foto, y cuentas de YouTube, Twitter y Twitch se obtienen por tu cuenta en Discord. Ver <1>FAQ</1> para más información.",
|
||||
"discordExplanation": "Tu nombre, foto, y cuentas de YouTube, Bluesky y Twitch se obtienen por tu cuenta en Discord. Ver <1>FAQ</1> para más información.",
|
||||
"favoriteBadge": "Insignia favorita",
|
||||
"battlefy": "Nombre de cuenta de Battlefy",
|
||||
|
||||
|
|
@ -43,7 +43,6 @@
|
|||
"forms.info.favoriteBadge": "Tu insignia favorita se muestra en forma grande en tu perfil.",
|
||||
"forms.info.battlefy": "El nombre de tu cuenta de Battlefy se utiliza para la clasificación y verificación en algunos torneos.",
|
||||
|
||||
"search.info": "Buscar usuarios usando su nombre en Discord, Splatoon 3 o Twitter",
|
||||
"search.noResults": "No se encontraron usuarios que coincidan con '{{query}}'",
|
||||
|
||||
"seasons": "Temporadas",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
"q5": "Est-ce qu'il y a une application sendou.ink ?",
|
||||
"a5": "Non, mais sendou.ink peut être installé en tant 'qu'Application Web Progressive' : vous pourrez bénéficier d'un mode plein écran, d'une icone et d'un processus séparé de votre navigateur. Pour pouvoir l'installer, n'hésitez pas à rechercher 'Comment installer une awp sur *votre natigateur*' sur Google.",
|
||||
|
||||
"q6": "Comment puis-je ajouter mes liens Twitch/Twitter/Youtube à mon profil ?",
|
||||
"q6": "Comment puis-je ajouter mes liens Twitch/Bluesky/Youtube à mon profil ?",
|
||||
"a6": "Nous utilisons le profil Discord pour ça. Connectez vos comptes sur Discord puis déconnectez et reconnectez vous sur sendou.ink pour les mettre à jour.",
|
||||
|
||||
"q7": "Comment puis-je ajouter des vidéos ?",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
"roles.BACKLINE": "Backline",
|
||||
"roles.FLEX": "Flex",
|
||||
"roles.COACH": "Coach",
|
||||
"forms.fields.teamTwitter": "Twitter de l'équipe",
|
||||
"forms.fields.bio": "Bio",
|
||||
"forms.fields.uploadImages": "Soumettre images",
|
||||
"forms.fields.uploadImages.pfp": "Emblème",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
"stick": "Stick",
|
||||
"sens": "Sens",
|
||||
"weaponPool": "Armes jouées",
|
||||
"discordExplanation": "Votre pseudo, votre photo de profil et vos comptes Youtube, Twitter et Twitch viennent de votre compte Discord. Voir la <1>FAQ</1> pour plus d'informations.",
|
||||
"discordExplanation": "Votre pseudo, votre photo de profil et vos comptes Youtube, Bluesky et Twitch viennent de votre compte Discord. Voir la <1>FAQ</1> pour plus d'informations.",
|
||||
"favoriteBadge": "Badge favori",
|
||||
|
||||
"forms.showDiscordUniqueName": "Montrer le pseudo Discord",
|
||||
|
|
@ -35,6 +35,5 @@
|
|||
"forms.errors.invalidSens": "La sensibilité du gyroscope ne peut pas être choisie si la sensibilité du stick droit ne l'est pas",
|
||||
"forms.info.favoriteBadge": "Votre badge favoris est affiché en grand par défaut sur votre profil.",
|
||||
|
||||
"search.info": "Rechercher des utilisateurs par le pseudo Discord, Splatoon 3 ou Twitter",
|
||||
"search.noResults": "Aucun utilisateur correspondant à '{{query}}' n'a été trouvé"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
"q5": "Est-ce qu'il y a une application sendou.ink ?",
|
||||
"a5": "Non, mais sendou.ink peut être installé en tant 'qu'Application Web Progressive' : vous pourrez bénéficier d'un mode plein écran, d'une icone et d'un processus séparé de votre navigateur. Pour pouvoir l'installer, n'hésitez pas à rechercher 'Comment installer une awp sur *votre natigateur*' sur Google.",
|
||||
|
||||
"q6": "Comment puis-je ajouter mes liens Twitch/Twitter/Youtube à mon profil ?",
|
||||
"q6": "Comment puis-je ajouter mes liens Twitch/Bluesky/Youtube à mon profil ?",
|
||||
"a6": "Nous utilisons le profil Discord pour ça. Connectez vos comptes sur Discord puis déconnectez et reconnectez vous sur sendou.ink pour les mettre à jour.",
|
||||
|
||||
"q7": "Comment puis-je ajouter des vidéos ?",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
"roles.BACKLINE": "Backline",
|
||||
"roles.FLEX": "Flex",
|
||||
"roles.COACH": "Coach",
|
||||
"forms.fields.teamTwitter": "Twitter de l'équipe",
|
||||
"forms.fields.bio": "Bio",
|
||||
"forms.fields.uploadImages": "Soumettre images",
|
||||
"forms.fields.uploadImages.pfp": "Emblème",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
"stick": "Stick",
|
||||
"sens": "Sens",
|
||||
"weaponPool": "Armes jouées",
|
||||
"discordExplanation": "Votre pseudo, votre photo de profil et vos comptes Youtube, Twitter et Twitch viennent de votre compte Discord. Voir la <1>FAQ</1> pour plus d'informations.",
|
||||
"discordExplanation": "Votre pseudo, votre photo de profil et vos comptes Youtube, Bluesky et Twitch viennent de votre compte Discord. Voir la <1>FAQ</1> pour plus d'informations.",
|
||||
"favoriteBadge": "Badge favori",
|
||||
|
||||
"forms.showDiscordUniqueName": "Montrer le pseudo Discord",
|
||||
|
|
@ -35,6 +35,5 @@
|
|||
"forms.errors.invalidSens": "La sensibilité du gyroscope ne peut pas être choisie si la sensibilité du stick droit ne l'est pas",
|
||||
"forms.info.favoriteBadge": "Votre badge favoris est affiché en grand par défaut sur votre profil.",
|
||||
|
||||
"search.info": "Rechercher des utilisateurs par le pseudo Discord, Splatoon 3 ou Twitter",
|
||||
"search.noResults": "Aucun utilisateur correspondant à '{{query}}' n'a été trouvé"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
"q5": "האם יש אפליקציית sendou.ink?",
|
||||
"a5": "לא, אבל ניתן להתקין את sendou.ink כ'אפליקציית אינטרנט מתקדמת' שמקבלת הרבה מאותן יתרונות כמו מסך מלא, אייקון במסך הבית ותהליך נפרד מהדפדפן. חפשו בגוגל 'כיצד להתקין PWA על *הדפדפן שלך*' כדי לראות איך.",
|
||||
|
||||
"q6": "איך להוסיף חשבון Twitch/Twitter/YouTube לפרופיל שלי?",
|
||||
"q6": "איך להוסיף חשבון Twitch/Bluesky/YouTube לפרופיל שלי?",
|
||||
"a6": "אנחנו משתמשים בפרופיל הדיסקורד שלכם בשביל זה. התחברו ואמתו אותם ב-Discord ואז צאו והיכנסו חזרה ל-sendou.ink כדי לעדכן אותם.",
|
||||
|
||||
"q7": "איך אני יכול להוסיף סרטונים?",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
"roles.BACKLINE": "קו אחורי",
|
||||
"roles.FLEX": "מעורב",
|
||||
"roles.COACH": "מאמן",
|
||||
"forms.fields.teamTwitter": "Twitter של הצוות",
|
||||
"forms.fields.bio": "ביו",
|
||||
"forms.fields.uploadImages": "העלאת תמונות",
|
||||
"forms.fields.uploadImages.pfp": "תמונת פרופיל",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
"stick": "סטיק",
|
||||
"sens": "רגישות",
|
||||
"weaponPool": "מאגר נשקים",
|
||||
"discordExplanation": "שם משתמש, תמונת פרופיל, חשבונות YouTube, Twitter ו-Twitch מגיעים מחשבון Discord שלך. ראו <1>שאלות נפוצות</1> למידע נוסף.",
|
||||
"discordExplanation": "שם משתמש, תמונת פרופיל, חשבונות YouTube, Bluesky ו-Twitch מגיעים מחשבון Discord שלך. ראו <1>שאלות נפוצות</1> למידע נוסף.",
|
||||
"favoriteBadge": "תג אהוב",
|
||||
|
||||
"forms.showDiscordUniqueName": "הראה שם משתמש Discord",
|
||||
|
|
@ -35,6 +35,5 @@
|
|||
"forms.errors.invalidSens": "לא ניתן להגדיר את רגישות התנועה אם רגישות הסטיק לא מוגדרת",
|
||||
"forms.info.favoriteBadge": "התג האהוב עליכם מוצג בגדול כברירת מחדל בפרופיל שלכם.",
|
||||
|
||||
"search.info": "חיפוש משתמשים לפי שם ב-Discord, Splatoon 3, או Twitter",
|
||||
"search.noResults": "לא נמצאו משתמשים התואמים '{{query}}'"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,6 @@
|
|||
"q5": "Esiste un app per sendou.ink?",
|
||||
"a5": "No, ma il sito può essere installato come una 'Progressive Web App', che porta un sacco degli stessi benefici come l'uso a schermo pieno, l'icona sulla schermata home e un processo separato dal browser. Cerca 'Come installare progressive web app su *il tuo browser*' per imparare come si fa.",
|
||||
|
||||
"q6": "Come faccio ad aggiungere un link per Twitch/Twitter/Youtube al mio profilo?",
|
||||
"q6": "Come faccio ad aggiungere un link per Twitch/Bluesky/Youtube al mio profilo?",
|
||||
"a6": "Il sito sincronizza i profili con le tue connessioni al profilo Discord. Per connettere un account a sendou.ink, connettilo e verificalo su Discord, quindi esci e riaccedi qui per aggiornare il profilo."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,5 @@
|
|||
"forms.errors.invalidCustomUrl.strangeCharacter": "URL personalizzato non può contenere caratteri speciali",
|
||||
"forms.errors.invalidCustomUrl.duplicate": "URL personalizzato gia in uso da un'altro utente",
|
||||
"forms.errors.invalidSens": "Sensitività giroscopio non può essere impostata se non hai impostato la sensitività del joystick destro",
|
||||
"search.info": "Cerca utenti con il nome Discord, Splatoon o Twitter",
|
||||
"search.noResults": "Nessun utente trovato per '{{query}}'"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@
|
|||
"auth.errors.aborted": "ログインを中断しました",
|
||||
"auth.errors.failed": "ログインに失敗しました",
|
||||
"auth.errors.discordPermissions": "sendou.ink は、Discord のプロファイル名、アバター、SNS連携をサイトのプロファイルに使用します。",
|
||||
"auth.errors.unknown": "ディスコードのアカウントにバリデートされたイーメールはありますか?助けが必要な場合ディスコードの #helpdeskチャンネルでお聞きください。:",
|
||||
|
||||
"footer.github.subtitle": "ソースコード",
|
||||
"footer.discord.subtitle": "ヘルプ & フィードバック",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
"q5": "sendou.ink のアプリはありますか?",
|
||||
"a5": "いいえ、でも sendou.inkは 'Progressive Web App' としてインストールすることができます。これは、フルスクリーン、ホーム画面へのアイコン、ブラウザからの分離など、アプリと同じ利点があります。'ブラウザへの pwa のインストール方法' でググってみてください。",
|
||||
|
||||
"q6": "Twitch/Twitter/YouTube はどうやって自分のプロファイルに追加できますか?",
|
||||
"q6": "Twitch/Bluesky/YouTube はどうやって自分のプロファイルに追加できますか?",
|
||||
"a6": "Discord のプロファイルに設定されているものを使用しています。Discord と連携+承認して、表示をリロードするために sendou.ink をログインし直してください。",
|
||||
|
||||
"q7": "動画はどうやって追加すればよいですか?",
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
"roles.SUB": "補欠",
|
||||
"roles.COACH": "コーチ",
|
||||
"roles.CHEERLEADER": "引き立て役(チアリーダー)",
|
||||
"forms.fields.teamTwitter": "チームの X(旧Twitter)",
|
||||
"forms.fields.teamBsky": "チームの Bluesky",
|
||||
"forms.fields.bio": "Bio",
|
||||
"forms.fields.uploadImages": "画像をアップロード",
|
||||
|
|
|
|||
|
|
@ -11,10 +11,9 @@
|
|||
"stick": "スティック",
|
||||
"sens": "感度",
|
||||
"weaponPool": "使用ブキ",
|
||||
"discordExplanation": "ユーザー名、プロファイル画像、YouTube、Twitter と Twitch アカウントは Discord のアカウントに設定されているものが使用されます。詳しくは <1>FAQ</1> をご覧ください。",
|
||||
"discordExplanation": "ユーザー名、プロファイル画像、YouTube、Bluesky と Twitch アカウントは Discord のアカウントに設定されているものが使用されます。詳しくは <1>FAQ</1> をご覧ください。",
|
||||
"favoriteBadge": "お気に入りバッジ",
|
||||
"battlefy": "Battlefyアカウント名",
|
||||
"bsky": "Blueskyアカウント名",
|
||||
|
||||
"forms.showDiscordUniqueName": "Discord のユーザー名を表示する",
|
||||
"forms.showDiscordUniqueName.info": "Discord のユニーク名 ({{discordUniqueName}}) 公表しますか?",
|
||||
|
|
@ -43,7 +42,6 @@
|
|||
"forms.info.favoriteBadge": "お気に入りバッジはデフォルトでプロファイルに大きく表示されます",
|
||||
"forms.info.battlefy": "Battlefyのアカウント名は特定のトーナメンでシーディング及びにプレイヤー情報の確認に使用されます。",
|
||||
|
||||
"search.info": "Discord, Splatoon 3, Twitter アカウント名でユーザーを検索する",
|
||||
"search.noResults": "該当ユーザーが見つかりません '{{query}}'",
|
||||
|
||||
"seasons": "シーズン",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,5 @@
|
|||
"q5": "Czy jest aplikacja sendou.ink?",
|
||||
"a5": "Nie, ale sendou.ink może być zainstalowane jako 'Progressive Web App', który ma wiele tych samych korzyści co normalna aplikacja. Wyszukaj 'jak się instaluje PWA na *twojej wyszukiwarce*' by wiedzieć jak.",
|
||||
|
||||
"q6": "Jak połączyć moje konto sendou.ink z moim Twitchem/Twitterem/Youtubem?",
|
||||
"a6": "Używamy do tego twojego profilu Discord. Połącz te konta na Discordzie i odśwież sendou.ink i powinny się pojawić."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
"roles.SUPPORT": "Support",
|
||||
"roles.BACKLINE": "Backline",
|
||||
"roles.COACH": "Trener",
|
||||
"forms.fields.teamTwitter": "Twitter drużyny",
|
||||
"forms.fields.bio": "Opis",
|
||||
"forms.fields.uploadImages": "Wstaw zdjęcia",
|
||||
"forms.fields.uploadImages.pfp": "Zdjęcie profilowe",
|
||||
|
|
|
|||
|
|
@ -27,6 +27,5 @@
|
|||
"forms.errors.invalidCustomUrl.duplicate": "Te niestandardowe URl jest już przez kogoś zajęte",
|
||||
"forms.errors.invalidSens": "Motion sens nie może być ustawione jeśli R-stick sens nie jest",
|
||||
|
||||
"search.info": "Wyszukaj kogoś poprzez ich nazwe na Discordzie, Splatoon 3 lub Twitterze",
|
||||
"search.noResults": "Nie znaleziono użytkownika o nazwie '{{query}}'"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
"auth.errors.aborted": "Login Abortado",
|
||||
"auth.errors.failed": "Login Falhou",
|
||||
"auth.errors.discordPermissions": "Para o seu perfil do sendou.ink, o site precisa de acesso ao nome do perfil do seu Discord, incluindo também o avatar e conexões sociais.",
|
||||
"auth.errors.unknown": "A sua conta do Discord possui um endereço de e-mail verificado? Para obter ajuda por favor entre em contato conosco (em inglês) pelo canal #helpdesk no nosso Discord:",
|
||||
|
||||
"footer.github.subtitle": "Código fonte",
|
||||
"footer.discord.subtitle": "Ajuda e Feedback",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"q5": "Existe um aplicativo do sendou.ink?",
|
||||
"a5": "Não mas, o sendou.ink pode ser instalado como um 'Aplicativo Web Progressivo' que possui muitos dos benefícios de um aplicativo tradicional tais como tela cheia, um ícone na tela inicial do seu dispositivo e um processo separado do navegador. Pesquise no Google 'como instalar AWP (PWA em Inglês) no *seu navegador*' para ver como.",
|
||||
|
||||
"q6": "Como adicionar o meu Twitch/Twitter/YouTube ao meu perfil?",
|
||||
"q6": "Como adicionar o meu Twitch/Bluesky/YouTube ao meu perfil?",
|
||||
"a6": "Nós usamos seu perfil do Discord para isso. Conecte e verifique seus perfis no Discord, depois saia e faça login novamente no sendou.ink para que o seu perfil atualize.",
|
||||
|
||||
"q7": "Como posso adicionar vídeos?",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
"roles.BACKLINE": "Linha de trás (backline)",
|
||||
"roles.FLEX": "Flex",
|
||||
"roles.COACH": "Treinador",
|
||||
"forms.fields.teamTwitter": "Twitter do Time",
|
||||
"forms.fields.bio": "Bio",
|
||||
"forms.fields.uploadImages": "Fazer upload de imagens",
|
||||
"forms.fields.uploadImages.pfp": "Imagem do perfil",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
"stick": "Analógico",
|
||||
"sens": "Sens",
|
||||
"weaponPool": "Seleção de armas",
|
||||
"discordExplanation": "Nome de usuário, foto de perfil, conta do YouTube, Twitter e Twitch vêm da sua conta do Discord. Veja o <1>Perguntas Frequentes</1> para mais informações.",
|
||||
"discordExplanation": "Nome de usuário, foto de perfil, conta do YouTube, Bluesky e Twitch vêm da sua conta do Discord. Veja o <1>Perguntas Frequentes</1> para mais informações.",
|
||||
"favoriteBadge": "Insígnia Favorita",
|
||||
|
||||
"forms.showDiscordUniqueName": "Mostrar nome de usuário Discord",
|
||||
|
|
@ -35,7 +35,6 @@
|
|||
"forms.errors.invalidSens": "A sensibilidade de Movimento não pode ser definida se a sensibilidade do Analógico Direito não está",
|
||||
"forms.info.favoriteBadge": "Por padrão, sua insígnia favorita é mostrada em tamanho maior no seu perfil.",
|
||||
|
||||
"search.info": "Procurar por usuários pelo nome do Discord, Splatoon 3 ou Twitter",
|
||||
"search.noResults": "Nenhum usuário encontrado com o termo '{{query}}'",
|
||||
|
||||
"seasons": "Temporadas",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,6 @@
|
|||
"q5": "Существует ли приложение sendou.ink?",
|
||||
"a5": "Нет, но sendou.ink может быть установлен как 'прогрессивное веб-приложение', которое дает такие преимущества как полноэкранный режим, иконка на домашнем экране и отдельный процесс от браузера. Для инструкции по установке вы можете указать в поисковике 'как установить pwa для *ваш браузер*'.",
|
||||
|
||||
"q6": "Как добавить ссылку на Twitch/Twitter/YouTube в моём профиле?",
|
||||
"q6": "Как добавить ссылку на Twitch/Bluesky/YouTube в моём профиле?",
|
||||
"a6": "Мы используем ваш профиль Discord для этого. Подключите и подтвердите нужный аккаунт в Discord, а затем выйдите и зайдите снова на sendou.ink для обновления ссылок."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
"roles.BACKLINE": "Бэклайн",
|
||||
"roles.FLEX": "Флекс",
|
||||
"roles.COACH": "Тренер",
|
||||
"forms.fields.teamTwitter": "Твиттер команды",
|
||||
"forms.fields.bio": "Описание",
|
||||
"forms.fields.uploadImages": "Загрузить изображения",
|
||||
"forms.fields.uploadImages.pfp": "Аватар команды",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
"stick": "Стик",
|
||||
"sens": "Чувствительность",
|
||||
"weaponPool": "Используемое оружие",
|
||||
"discordExplanation": "Имя пользователя, аватар, ссылка на аккаунты YouTube, Twitter и Twitch берутся из вашего аккаунта в Discord. Посмотрите <1>FAQ</1> для дополнительной информации.",
|
||||
"discordExplanation": "Имя пользователя, аватар, ссылка на аккаунты YouTube, Bluesky и Twitch берутся из вашего аккаунта в Discord. Посмотрите <1>FAQ</1> для дополнительной информации.",
|
||||
"favoriteBadge": "Любимый значок",
|
||||
|
||||
"forms.showDiscordUniqueName": "Показать пользовательское имя Discord",
|
||||
|
|
@ -35,7 +35,6 @@
|
|||
"forms.errors.invalidSens": "Чувствительность наклона не может быть указана, если не указана чувствительность стика",
|
||||
"forms.info.favoriteBadge": "По умолчанию ваш любимый значок отображён большим в вашем профиле.",
|
||||
|
||||
"search.info": "Поиск пользователей по имени в Discord, Splatoon 3 или Twitter",
|
||||
"search.noResults": "Не найден пользователь по запросу '{{query}}'",
|
||||
|
||||
"seasons": "Сезоны",
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
"auth.errors.aborted": "登录中止",
|
||||
"auth.errors.failed": "登录失败",
|
||||
"auth.errors.discordPermissions": "为了完善您的sendou.ink个人资料,网站需要获取您的Discord名字、头像和社交链接。",
|
||||
"auth.errors.unknown": "您的Discord账号验证过邮箱吗?请在我们的Discord服务器的#helpdesk频道获取帮助:",
|
||||
|
||||
"footer.github.subtitle": "源代码",
|
||||
"footer.discord.subtitle": "帮助及反馈",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"q5": "sendou.ink有专门的APP吗?",
|
||||
"a5": "没有,但是可以将sendou.ink下载为渐进式网络应用程序(PWA),这样就能获得全屏使用、主页图标以及和网页端不同的操作方式。搜索如何在您的浏览器下载PWA来查看具体操作步骤。",
|
||||
|
||||
"q6": "如何在我的个人资料里添加Twitch/Twitter/YouTube?",
|
||||
"q6": "如何在我的个人资料里添加Twitch/Bluesky/YouTube?",
|
||||
"a6": "我们通过您的Discord资料来添加这些信息。将这些账号和您的Discord绑定,登出再登录sendou.ink后即可更新。",
|
||||
|
||||
"q7": "我应该如何添加视频?",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
"roles.BACKLINE": "后排",
|
||||
"roles.FLEX": "自由人",
|
||||
"roles.COACH": "教练",
|
||||
"forms.fields.teamTwitter": "队伍Twitter",
|
||||
"forms.fields.bio": "简介",
|
||||
"forms.fields.uploadImages": "上传图片",
|
||||
"forms.fields.uploadImages.pfp": "头像",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"stick": "摇杆",
|
||||
"sens": "感度",
|
||||
"weaponPool": "武器池",
|
||||
"discordExplanation": "用户名、头像、Youtube、Twitter和Twitch账号皆来自您的Discord账号。查看 <1>FAQ</1> 以获得更多相关信息。",
|
||||
"discordExplanation": "用户名、头像、Youtube、Bluesky和Twitch账号皆来自您的Discord账号。查看 <1>FAQ</1> 以获得更多相关信息。",
|
||||
"favoriteBadge": "最喜爱的徽章",
|
||||
"battlefy": "Battlefy用户名",
|
||||
|
||||
|
|
@ -42,7 +42,6 @@
|
|||
"forms.info.favoriteBadge": "您最喜爱的徽章将会默认在资料页展示为大徽章",
|
||||
"forms.info.battlefy": "Battlefy用户名会在部分比赛被用于种子排名和验证",
|
||||
|
||||
"search.info": "通过Discord、斯普拉遁3或Twitter名称查找用户",
|
||||
"search.noResults": "没有符合 '{{query}}' 的用户",
|
||||
|
||||
"seasons": "赛季",
|
||||
|
|
|
|||
8
migrations/079-remove-twitter.js
Normal file
8
migrations/079-remove-twitter.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export function up(db) {
|
||||
db.transaction(() => {
|
||||
db.prepare(/* sql */ `alter table "User" drop column "twitter"`).run();
|
||||
db.prepare(/* sql */ `alter table "AllTeam" drop column "twitter"`).run();
|
||||
|
||||
db.prepare(/* sql */ `update "User" set "bsky" = null`).run();
|
||||
})();
|
||||
}
|
||||
126
package-lock.json
generated
126
package-lock.json
generated
|
|
@ -60,8 +60,8 @@
|
|||
"react-use": "^17.6.0",
|
||||
"react-use-draggable-scroll": "^0.4.7",
|
||||
"reconnecting-websocket": "^4.4.0",
|
||||
"remix-auth": "^3.7.0",
|
||||
"remix-auth-oauth2": "^1.11.2",
|
||||
"remix-auth": "^4.1.0",
|
||||
"remix-auth-oauth2": "^3.2.2",
|
||||
"remix-i18next": "^6.4.1",
|
||||
"remix-utils": "^7.7.0",
|
||||
"slugify": "^1.6.6",
|
||||
|
|
@ -1864,6 +1864,18 @@
|
|||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@edgefirst-dev/data": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@edgefirst-dev/data/-/data-0.0.2.tgz",
|
||||
"integrity": "sha512-kvw7RRDW9TJtOYHhzMYQ4g9x+ji87o02CROTnS9qCl2SZXauAPRpTiIQMGC5YLwvgzxV76Y2uMavQK4TQB1z0Q==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/sergiodxa"
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/hash": {
|
||||
"version": "0.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
|
||||
|
|
@ -2583,6 +2595,12 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/@mjackson/headers": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@mjackson/headers/-/headers-0.9.0.tgz",
|
||||
"integrity": "sha512-1WFCu2iRaqbez9hcYYI611vcH1V25R+fDfOge/CyKc8sdbzniGfy/FRhNd3DgvFF4ZEEX2ayBrvFHLtOpfvadw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@npmcli/fs": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz",
|
||||
|
|
@ -2658,6 +2676,52 @@
|
|||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oslojs/asn1": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@oslojs/asn1/-/asn1-1.0.0.tgz",
|
||||
"integrity": "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@oslojs/binary": "1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oslojs/binary": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@oslojs/binary/-/binary-1.0.0.tgz",
|
||||
"integrity": "sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@oslojs/crypto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@oslojs/crypto/-/crypto-1.0.1.tgz",
|
||||
"integrity": "sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@oslojs/asn1": "1.0.0",
|
||||
"@oslojs/binary": "1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@oslojs/encoding": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz",
|
||||
"integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@oslojs/jwt": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@oslojs/jwt/-/jwt-0.2.0.tgz",
|
||||
"integrity": "sha512-bLE7BtHrURedCn4Mco3ma9L4Y1GR2SMBuIvjWr7rmQ4/W/4Jy70TIAgZ+0nIlk0xHz1vNP8x8DCns45Sb2XRbg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@oslojs/encoding": "0.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@oslojs/jwt/node_modules/@oslojs/encoding": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-0.4.1.tgz",
|
||||
"integrity": "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
|
|
@ -7881,6 +7945,17 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/arctic": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/arctic/-/arctic-3.2.1.tgz",
|
||||
"integrity": "sha512-lvOfv088aiaNCN4bGpnVd0cJmQKUkB2gGaZeA3lTwbBZVj69+zd/LpBPO6CXNCyX45CKqqcaOV6J7HeJ1k4hEA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@oslojs/crypto": "1.0.1",
|
||||
"@oslojs/encoding": "1.1.0",
|
||||
"@oslojs/jwt": "0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/arg": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
||||
|
|
@ -14625,39 +14700,36 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/remix-auth": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/remix-auth/-/remix-auth-3.7.0.tgz",
|
||||
"integrity": "sha512-2QVjp2nJVaYxuFBecMQwzixCO7CLSssttLBU5eVlNcNlVeNMmY1g7OkmZ1Ogw9sBcoMXZ18J7xXSK0AISVFcfQ==",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/remix-auth/-/remix-auth-4.1.0.tgz",
|
||||
"integrity": "sha512-Xdy42clt+g79GCn+Wl1+B6S/yWnvrStnk62vo1pGuRuUwHC+pjmeEE52ZRkRPuhLGqsQnoDD9TVz/wfEJAGF8g==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/sergiodxa"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@remix-run/react": "^1.0.0 || ^2.0.0",
|
||||
"@remix-run/server-runtime": "^1.0.0 || ^2.0.0"
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/remix-auth-oauth2": {
|
||||
"version": "1.11.2",
|
||||
"resolved": "https://registry.npmjs.org/remix-auth-oauth2/-/remix-auth-oauth2-1.11.2.tgz",
|
||||
"integrity": "sha512-5ORP+LMi5CVCA/Wb8Z+FCAJ73Uiy4uyjEzhlVwNBfdAkPOnfxzoi+q/pY/CrueYv3OniCXRM35ZYqkVi3G1UPw==",
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/remix-auth-oauth2/-/remix-auth-oauth2-3.2.2.tgz",
|
||||
"integrity": "sha512-m4jb7ZTFau4UcTEfuZQ+SPrXvXQSR8nrcAxww4ddxyvGHZglSeSYPqdwC81gMeEgIxDEgHULZgRfklV4wqJ4fA==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/sergiodxa"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
"uuid": "^9.0.1"
|
||||
"@edgefirst-dev/data": "^0.0.2",
|
||||
"@mjackson/headers": "^0.9.0",
|
||||
"arctic": "^3.0.0",
|
||||
"debug": "^4.3.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.0.0 || >=20.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@remix-run/server-runtime": "^1.0.0 || ^2.0.0",
|
||||
"remix-auth": "^3.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/remix-auth/node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
"remix-auth": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/remix-i18next": {
|
||||
|
|
|
|||
|
|
@ -76,8 +76,8 @@
|
|||
"react-use": "^17.6.0",
|
||||
"react-use-draggable-scroll": "^0.4.7",
|
||||
"reconnecting-websocket": "^4.4.0",
|
||||
"remix-auth": "^3.7.0",
|
||||
"remix-auth-oauth2": "^1.11.2",
|
||||
"remix-auth": "^4.1.0",
|
||||
"remix-auth-oauth2": "^3.2.2",
|
||||
"remix-i18next": "^6.4.1",
|
||||
"remix-utils": "^7.7.0",
|
||||
"slugify": "^1.6.6",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user