diff --git a/apps/admin-dashboard/app/root.tsx b/apps/admin-dashboard/app/root.tsx index 7d4ee924..ae012f8c 100644 --- a/apps/admin-dashboard/app/root.tsx +++ b/apps/admin-dashboard/app/root.tsx @@ -10,6 +10,7 @@ import { } from '@remix-run/react'; import { withSentry } from '@sentry/remix'; +import { buildMeta } from '@oyster/core/remix'; import { Toast } from '@oyster/ui'; import uiStylesheet from '@oyster/ui/index.css?url'; @@ -25,17 +26,10 @@ export const links: LinksFunction = () => { }; export const meta: MetaFunction = () => { - const title = 'Admin Dashboard'; - - const description = - 'Your home for all things ColorStack administration. Manage applications, events and more!'; - - return [ - { title }, - { name: 'description', content: description }, - { property: 'og:title', content: title }, - { property: 'og:description', content: description }, - ]; + return buildMeta({ + description: `Your home for all things ColorStack administration. Manage applications, events and more!`, + title: 'Admin Dashboard', + }); }; export async function loader({ request }: LoaderFunctionArgs) { diff --git a/apps/member-profile/app/root.tsx b/apps/member-profile/app/root.tsx index 7b13528b..28919d44 100644 --- a/apps/member-profile/app/root.tsx +++ b/apps/member-profile/app/root.tsx @@ -10,6 +10,7 @@ import { } from '@remix-run/react'; import { withSentry } from '@sentry/remix'; +import { buildMeta } from '@oyster/core/remix'; import { Toast } from '@oyster/ui'; import uiStylesheet from '@oyster/ui/index.css?url'; @@ -25,17 +26,10 @@ export const links: LinksFunction = () => { }; export const meta: MetaFunction = () => { - const title = 'Member Profile'; - - const description = - 'Your home for all things ColorStack membership. Manage your profile and more!'; - - return [ - { title }, - { name: 'description', content: description }, - { property: 'og:title', content: title }, - { property: 'og:description', content: description }, - ]; + return buildMeta({ + description: `Your home for all things ColorStack membership. Manage your profile and more!`, + title: 'Member Profile', + }); }; export async function loader({ request }: LoaderFunctionArgs) { diff --git a/apps/member-profile/app/routes/_profile.profile.emails.tsx b/apps/member-profile/app/routes/_profile.profile.emails.tsx index 687c4487..c3b0f3b9 100644 --- a/apps/member-profile/app/routes/_profile.profile.emails.tsx +++ b/apps/member-profile/app/routes/_profile.profile.emails.tsx @@ -2,6 +2,7 @@ import { type ActionFunctionArgs, json, type LoaderFunctionArgs, + type MetaFunction, } from '@remix-run/node'; import { Outlet, @@ -14,6 +15,7 @@ import { import { Edit, Plus } from 'react-feather'; import { z } from 'zod'; +import { buildMeta } from '@oyster/core/remix'; import { db } from '@oyster/db'; import { Button, @@ -41,6 +43,13 @@ import { user, } from '@/shared/session.server'; +export const meta: MetaFunction = () => { + return buildMeta({ + description: 'Manage your email addresses and email sharing settings.', + title: 'Email Addresses', + }); +}; + export async function loader({ request }: LoaderFunctionArgs) { const session = await ensureUserAuthenticated(request); diff --git a/apps/member-profile/app/routes/_public.apply._index.tsx b/apps/member-profile/app/routes/_public.apply._index.tsx index c113005a..fde24b72 100644 --- a/apps/member-profile/app/routes/_public.apply._index.tsx +++ b/apps/member-profile/app/routes/_public.apply._index.tsx @@ -7,6 +7,7 @@ import { import { Form as RemixForm, useActionData } from '@remix-run/react'; import { z } from 'zod'; +import { buildMeta } from '@oyster/core/remix'; import { Application as ApplicationType } from '@oyster/types'; import { Button, @@ -25,18 +26,11 @@ import { Route } from '@/shared/constants'; import { commitSession, getSession } from '@/shared/session.server'; export const meta: MetaFunction = () => { - const title = 'Apply to ColorStack'; - - const description = - 'Apply to join the largest community of Black and Latinx Computer Science college students.'; - - return [ - { title }, - { name: 'description', content: description }, - { property: 'og:title', content: title }, - { property: 'og:description', content: description }, - { property: 'og:image', content: '/images/og_apply.jpg' }, - ]; + return buildMeta({ + description: `Apply to join the largest community of Black and Latinx Computer Science college students.`, + image: '/images/og_apply.jpg', + title: 'Apply to ColorStack', + }); }; const ApplyInput = ApplicationType.pick({ diff --git a/packages/core/package.json b/packages/core/package.json index c987a3de..019d22f7 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -26,6 +26,7 @@ "./location.ui": "./src/modules/location/location.ui.tsx", "./mixpanel": "./src/modules/mixpanel/index.ts", "./object-storage": "./src/modules/object-storage/index.ts", + "./remix": "./src/modules/remix.ts", "./resources": "./src/modules/resource/index.ts", "./resources.server": "./src/modules/resource/index.server.ts", "./resume-books": "./src/modules/resume-book/resume-book.core.ts", diff --git a/packages/core/src/modules/remix.ts b/packages/core/src/modules/remix.ts new file mode 100644 index 00000000..a35620cf --- /dev/null +++ b/packages/core/src/modules/remix.ts @@ -0,0 +1,31 @@ +import { type MetaDescriptor } from '@remix-run/node'; + +type BuildMetaInput = { + description: string; + image?: string; + title: string; +}; + +/** + * Builds the meta descriptors for a page. The title and description are + * required, but the image is optional. If more properties are needed, they can + * be appended to the return value. + */ +export function buildMeta({ + description, + image, + title, +}: BuildMetaInput): MetaDescriptor[] { + const meta = [ + { title }, + { name: 'description', content: description }, + { property: 'og:title', content: title }, + { property: 'og:description', content: description }, + ]; + + if (image) { + meta.push({ property: 'og:image', content: image }); + } + + return meta; +}