diff --git a/app/components/layout/nav-items.json b/app/components/layout/nav-items.json index 579fb6f9f..644cf0082 100644 --- a/app/components/layout/nav-items.json +++ b/app/components/layout/nav-items.json @@ -88,5 +88,13 @@ "invert(30%) sepia(73%) saturate(4089%) hue-rotate(326deg) brightness(96%) contrast(104%)", "invert(55%) sepia(20%) saturate(738%) hue-rotate(224deg) brightness(86%) contrast(88%)" ] + }, + { + "name": "t", + "url": "t", + "filters": [ + "invert(99%) sepia(3%) saturate(615%) hue-rotate(199deg) brightness(115%) contrast(88%)", + "invert(23%) sepia(90%) saturate(2049%) hue-rotate(329deg) brightness(95%) contrast(107%)" + ] } ] diff --git a/app/features/img-upload/s3.server.ts b/app/features/img-upload/s3.server.ts index 3578ae055..d5175db30 100644 --- a/app/features/img-upload/s3.server.ts +++ b/app/features/img-upload/s3.server.ts @@ -8,27 +8,45 @@ import { writeAsyncIterableToWritable } from "@remix-run/node"; import { nanoid } from "nanoid"; import invariant from "tiny-invariant"; -const { - STORAGE_END_POINT, - STORAGE_ACCESS_KEY, - STORAGE_SECRET, - STORAGE_REGION, - STORAGE_BUCKET, -} = process.env; +const envVars = () => { + const { + STORAGE_END_POINT, + STORAGE_ACCESS_KEY, + STORAGE_SECRET, + STORAGE_REGION, + STORAGE_BUCKET, + } = process.env; -if ( - !( - STORAGE_ACCESS_KEY && - STORAGE_END_POINT && - STORAGE_SECRET && - STORAGE_REGION && - STORAGE_BUCKET - ) -) { - throw new Error(`Storage is missing required configuration.`); -} + if ( + !( + STORAGE_ACCESS_KEY && + STORAGE_END_POINT && + STORAGE_SECRET && + STORAGE_REGION && + STORAGE_BUCKET + ) + ) { + throw new Error(`Storage is missing required configuration.`); + } + + return { + STORAGE_END_POINT, + STORAGE_ACCESS_KEY, + STORAGE_SECRET, + STORAGE_REGION, + STORAGE_BUCKET, + }; +}; const uploadStream = ({ Key }: Pick) => { + const { + STORAGE_END_POINT, + STORAGE_ACCESS_KEY, + STORAGE_SECRET, + STORAGE_REGION, + STORAGE_BUCKET, + } = envVars(); + const s3 = new AWS.S3({ endpoint: STORAGE_END_POINT, s3ForcePathStyle: false, diff --git a/app/features/team/routes/t.$customUrl.edit.tsx b/app/features/team/routes/t.$customUrl.edit.tsx index 31d8eeb44..7b2f4c8f1 100644 --- a/app/features/team/routes/t.$customUrl.edit.tsx +++ b/app/features/team/routes/t.$customUrl.edit.tsx @@ -1,4 +1,8 @@ -import type { LinksFunction } from "@remix-run/node"; +import type { + LinksFunction, + MetaFunction, + SerializeFrom, +} from "@remix-run/node"; import { type LoaderArgs, redirect, @@ -20,6 +24,7 @@ import { } from "~/utils/remix"; import { mySlugify, + navIconUrl, teamPage, TEAM_SEARCH_PAGE, uploadImagePage, @@ -35,18 +40,41 @@ import { deleteTeam } from "../queries/deleteTeam.server"; import { Button } from "~/components/Button"; import { assertUnreachable } from "~/utils/types"; import styles from "../team.css"; +import { makeTitle } from "~/utils/strings"; export const links: LinksFunction = () => { return [{ rel: "stylesheet", href: styles }]; }; +export const meta: MetaFunction = ({ + data, +}: { + data: SerializeFrom; +}) => { + if (!data) return {}; + + return { + title: makeTitle(data.team.name), + }; +}; + export const handle: SendouRouteHandle = { i18n: ["team"], - // breadcrumb: () => ({ - // imgPath: navIconUrl("object-damage-calculator"), - // href: OBJECT_DAMAGE_CALCULATOR_URL, - // type: "IMAGE", - // }), + breadcrumb: ({ match }) => { + const data = match.data as SerializeFrom; + return [ + { + imgPath: navIconUrl("t"), + href: TEAM_SEARCH_PAGE, + type: "IMAGE", + }, + { + text: data.team.name, + href: teamPage(data.team.customUrl), + type: "TEXT", + }, + ]; + }, }; export const action: ActionFunction = async ({ request, params }) => { diff --git a/app/features/team/routes/t.$customUrl.join.tsx b/app/features/team/routes/t.$customUrl.join.tsx index 219fff8de..44a601aad 100644 --- a/app/features/team/routes/t.$customUrl.join.tsx +++ b/app/features/team/routes/t.$customUrl.join.tsx @@ -12,8 +12,8 @@ import { useTranslation } from "~/hooks/useTranslation"; import { requireUser } from "~/modules/auth"; import { notFoundIfFalsy, - type SendouRouteHandle, validate, + type SendouRouteHandle, } from "~/utils/remix"; import { teamPage } from "~/utils/urls"; import { addNewTeamMember } from "../queries/addNewTeamMember.server"; @@ -53,11 +53,6 @@ export const action: ActionFunction = async ({ request, params }) => { export const handle: SendouRouteHandle = { i18n: ["team"], - // breadcrumb: () => ({ - // imgPath: navIconUrl("object-damage-calculator"), - // href: OBJECT_DAMAGE_CALCULATOR_URL, - // type: "IMAGE", - // }), }; export const loader = async ({ request, params }: LoaderArgs) => { diff --git a/app/features/team/routes/t.$customUrl.roster.tsx b/app/features/team/routes/t.$customUrl.roster.tsx index d949829fd..df87206f0 100644 --- a/app/features/team/routes/t.$customUrl.roster.tsx +++ b/app/features/team/routes/t.$customUrl.roster.tsx @@ -1,4 +1,8 @@ -import type { LinksFunction } from "@remix-run/node"; +import type { + LinksFunction, + MetaFunction, + SerializeFrom, +} from "@remix-run/node"; import { redirect, type ActionFunction, @@ -18,9 +22,14 @@ import { useTranslation } from "~/hooks/useTranslation"; import { requireUser, useUser } from "~/modules/auth"; import type { SendouRouteHandle } from "~/utils/remix"; import { notFoundIfFalsy, parseRequestFormData, validate } from "~/utils/remix"; -import { discordFullName } from "~/utils/strings"; +import { discordFullName, makeTitle } from "~/utils/strings"; import { assertUnreachable } from "~/utils/types"; -import { joinTeamPage, teamPage } from "~/utils/urls"; +import { + joinTeamPage, + navIconUrl, + teamPage, + TEAM_SEARCH_PAGE, +} from "~/utils/urls"; import { editRole } from "../queries/editRole.server"; import { findByIdentifier } from "../queries/findByIdentifier.server"; import { inviteCodeById } from "../queries/inviteCodeById.server"; @@ -37,6 +46,18 @@ export const links: LinksFunction = () => { return [{ rel: "stylesheet", href: styles }]; }; +export const meta: MetaFunction = ({ + data, +}: { + data: SerializeFrom; +}) => { + if (!data) return {}; + + return { + title: makeTitle(data.team.name), + }; +}; + export const action: ActionFunction = async ({ request, params }) => { const user = await requireUser(request); @@ -86,11 +107,21 @@ export const action: ActionFunction = async ({ request, params }) => { export const handle: SendouRouteHandle = { i18n: ["team"], - // breadcrumb: () => ({ - // imgPath: navIconUrl("object-damage-calculator"), - // href: OBJECT_DAMAGE_CALCULATOR_URL, - // type: "IMAGE", - // }), + breadcrumb: ({ match }) => { + const data = match.data as SerializeFrom; + return [ + { + imgPath: navIconUrl("t"), + href: TEAM_SEARCH_PAGE, + type: "IMAGE", + }, + { + text: data.team.name, + href: teamPage(data.team.customUrl), + type: "TEXT", + }, + ]; + }, }; export const loader = async ({ request, params }: LoaderArgs) => { diff --git a/app/features/team/routes/t.$customUrl.tsx b/app/features/team/routes/t.$customUrl.tsx index c2406d0d6..6bea1e8e0 100644 --- a/app/features/team/routes/t.$customUrl.tsx +++ b/app/features/team/routes/t.$customUrl.tsx @@ -23,6 +23,9 @@ import { makeTitle } from "~/utils/strings"; import { editTeamPage, manageTeamRosterPage, + navIconUrl, + teamPage, + TEAM_SEARCH_PAGE, userPage, userSubmittedImage, } from "~/utils/urls"; @@ -65,11 +68,21 @@ export const action: ActionFunction = async ({ request, params }) => { export const handle: SendouRouteHandle = { i18n: ["team"], - // breadcrumb: () => ({ - // imgPath: navIconUrl("object-damage-calculator"), - // href: OBJECT_DAMAGE_CALCULATOR_URL, - // type: "IMAGE", - // }), + breadcrumb: ({ match }) => { + const data = match.data as SerializeFrom; + return [ + { + imgPath: navIconUrl("t"), + href: TEAM_SEARCH_PAGE, + type: "IMAGE", + }, + { + text: data.team.name, + href: teamPage(data.team.customUrl), + type: "TEXT", + }, + ]; + }, }; export const loader = ({ params }: LoaderArgs) => { diff --git a/app/features/team/routes/t.tsx b/app/features/team/routes/t.tsx index c74758580..8edba0a6a 100644 --- a/app/features/team/routes/t.tsx +++ b/app/features/team/routes/t.tsx @@ -2,6 +2,8 @@ import type { ActionFunction, LinksFunction, LoaderArgs, + MetaFunction, + SerializeFrom, } from "@remix-run/node"; import { redirect } from "@remix-run/node"; import { @@ -21,11 +23,14 @@ import { Main } from "~/components/Main"; import { SubmitButton } from "~/components/SubmitButton"; import { useTranslation } from "~/hooks/useTranslation"; import { getUser, requireUser, useUser } from "~/modules/auth"; +import { i18next } from "~/modules/i18n"; import { joinListToNaturalString } from "~/utils/arrays"; import type { SendouRouteHandle } from "~/utils/remix"; import { parseRequestFormData, validate } from "~/utils/remix"; +import { makeTitle } from "~/utils/strings"; import { mySlugify, + navIconUrl, teamPage, TEAM_SEARCH_PAGE, userSubmittedImage, @@ -36,6 +41,18 @@ import { TEAM } from "../team-constants"; import { createTeamSchema } from "../team-schemas.server"; import styles from "../team.css"; +export const meta: MetaFunction = ({ + data, +}: { + data: SerializeFrom; +}) => { + if (!data) return {}; + + return { + title: data.title, + }; +}; + export const links: LinksFunction = () => { return [{ rel: "stylesheet", href: styles }]; }; @@ -73,15 +90,16 @@ export const action: ActionFunction = async ({ request }) => { export const handle: SendouRouteHandle = { i18n: ["team"], - // breadcrumb: () => ({ - // imgPath: navIconUrl("object-damage-calculator"), - // href: OBJECT_DAMAGE_CALCULATOR_URL, - // type: "IMAGE", - // }), + breadcrumb: () => ({ + imgPath: navIconUrl("t"), + href: TEAM_SEARCH_PAGE, + type: "IMAGE", + }), }; export const loader = async ({ request }: LoaderArgs) => { const user = await getUser(request); + const t = await i18next.getFixedT(request); const teams = allTeams().sort((teamA, teamB) => { // show own team first always @@ -122,6 +140,7 @@ export const loader = async ({ request }: LoaderArgs) => { }); return { + title: makeTitle(t("pages.t")), teams, isMemberOfTeam: !user ? false diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 9c91329e1..3c2a7b9ff 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -14,6 +14,7 @@ "pages.object-damage-calculator": "DMG Calc", "pages.myPage": "My Page", "pages.u": "User Search", + "pages.t": "Teams", "header.profile": "Profile", "header.logout": "Log out", diff --git a/public/static-assets/img/layout/t.avif b/public/static-assets/img/layout/t.avif new file mode 100644 index 000000000..139b6dd22 Binary files /dev/null and b/public/static-assets/img/layout/t.avif differ diff --git a/public/static-assets/img/layout/t.png b/public/static-assets/img/layout/t.png new file mode 100644 index 000000000..55a83a274 Binary files /dev/null and b/public/static-assets/img/layout/t.png differ