mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-04-09 17:18:26 -04:00
Add SEO (including better tab titles)
This commit is contained in:
@@ -3,6 +3,8 @@ import {Col} from "web/components/layout/col";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import React from "react";
|
||||
import Link from "next/link";
|
||||
import {SEO} from "web/components/SEO";
|
||||
import {capitalize} from "lodash";
|
||||
|
||||
type Props = {
|
||||
content: string;
|
||||
@@ -26,8 +28,14 @@ const MarkdownLink = ({href, children}: { href?: string; children: React.ReactNo
|
||||
}
|
||||
|
||||
export default function MarkdownPage({content, filename}: Props) {
|
||||
const title = /[A-Z]/.test(filename) ? filename : capitalize(filename)
|
||||
return (
|
||||
<PageBase trackPageView={filename} className={'col-span-8'}>
|
||||
<SEO
|
||||
title={title}
|
||||
description={title}
|
||||
url={`/` + filename}
|
||||
/>
|
||||
<Col className="items-center">
|
||||
<Col className='w-full rounded px-3 py-4 sm:px-6 space-y-4 custom-link'>
|
||||
<ReactMarkdown
|
||||
|
||||
@@ -6,10 +6,17 @@ import { Col } from 'web/components/layout/col'
|
||||
import { Title } from 'web/components/widgets/title'
|
||||
import { ExternalLinkIcon } from '@heroicons/react/outline'
|
||||
import {discordLink, formLink, githubIssues} from "common/constants";
|
||||
import {SEO} from "web/components/SEO";
|
||||
import React from "react";
|
||||
|
||||
export default function Custom404(props: { customText?: string }) {
|
||||
return (
|
||||
<PageBase trackPageView={'404'}>
|
||||
<SEO
|
||||
title={'Not Found'}
|
||||
description={'Not Found'}
|
||||
url={`/404`}
|
||||
/>
|
||||
<Custom404Content customText={props.customText} />
|
||||
</PageBase>
|
||||
)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import {PageBase} from 'web/components/page-base'
|
||||
import {ReactNode} from "react";
|
||||
import React, {ReactNode} from "react";
|
||||
import Link from "next/link";
|
||||
import {discordLink, formLink, githubRepo} from "common/constants";
|
||||
import {SEO} from "web/components/SEO";
|
||||
|
||||
|
||||
export const AboutBlock = (props: {
|
||||
@@ -18,6 +19,11 @@ export const AboutBlock = (props: {
|
||||
export default function About() {
|
||||
return (
|
||||
<PageBase trackPageView={'about'}>
|
||||
<SEO
|
||||
title={'About'}
|
||||
description={'About Compass'}
|
||||
url={`/about`}
|
||||
/>
|
||||
<div className="text-gray-600 dark:text-white min-h-screen p-6">
|
||||
<div className="w-full">
|
||||
<div className="relative py-8 mb-8 overflow-hidden">
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import {PageBase} from 'web/components/page-base'
|
||||
import {Col} from 'web/components/layout/col'
|
||||
import {SEO} from "web/components/SEO";
|
||||
import React from "react";
|
||||
|
||||
export default function ConfirmEmail() {
|
||||
return (
|
||||
<PageBase trackPageView={'private messages page'}>
|
||||
<SEO
|
||||
title={'Confirm Email'}
|
||||
description={'Confirm your email'}
|
||||
url={`/confirm-email`}
|
||||
/>
|
||||
<Col className="items-center justify-center h-full">
|
||||
<div className="text-xl font-semibold text-center mt-8">
|
||||
Thank you for confirming your email!
|
||||
|
||||
@@ -8,12 +8,12 @@ const FILENAME = __filename.split('/').pop()?.split('.').shift();
|
||||
export async function getStaticProps() {
|
||||
const filePath = path.join(process.cwd(), 'public', 'md', FILENAME + '.md');
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
return {props: {content}};
|
||||
return {props: {content, filename: FILENAME}};
|
||||
}
|
||||
|
||||
type Props = { content: string };
|
||||
type Props = { content: string, filename: string };
|
||||
|
||||
export default function Faq({content}: Props) {
|
||||
if (!FILENAME) throw new Error('Could not determine filename');
|
||||
return <MarkdownPage content={content} filename={FILENAME}></MarkdownPage>
|
||||
export default function Page({content, filename}: Props) {
|
||||
if (!filename) throw new Error('Could not determine filename');
|
||||
return <MarkdownPage content={content} filename={filename}></MarkdownPage>
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {ContactComponent} from "web/components/contact";
|
||||
export default function ContactPage() {
|
||||
return (
|
||||
<PageBase
|
||||
trackPageView={'vote page'}
|
||||
trackPageView={'contact page'}
|
||||
className={'relative p-2 sm:pt-0'}
|
||||
>
|
||||
<SEO
|
||||
|
||||
@@ -7,12 +7,12 @@ const FILENAME = __filename.split('/').pop()?.split('.').shift();
|
||||
export async function getStaticProps() {
|
||||
const filePath = path.join(process.cwd(), 'public', 'md', FILENAME + '.md');
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
return {props: {content}};
|
||||
return {props: {content, filename: FILENAME}};
|
||||
}
|
||||
|
||||
type Props = { content: string };
|
||||
type Props = { content: string, filename: string };
|
||||
|
||||
export default function Faq({content}: Props) {
|
||||
if (!FILENAME) throw new Error('Could not determine filename');
|
||||
return <MarkdownPage content={content} filename={FILENAME}></MarkdownPage>
|
||||
}
|
||||
export default function Page({content, filename}: Props) {
|
||||
if (!filename) throw new Error('Could not determine filename');
|
||||
return <MarkdownPage content={content} filename={filename.toUpperCase()}></MarkdownPage>
|
||||
}
|
||||
@@ -8,12 +8,12 @@ const FILENAME = __filename.split('/').pop()?.split('.').shift();
|
||||
export async function getStaticProps() {
|
||||
const filePath = path.join(process.cwd(), 'public', 'md', FILENAME + '.md');
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
return {props: {content}};
|
||||
return {props: {content, filename: FILENAME}};
|
||||
}
|
||||
|
||||
type Props = { content: string };
|
||||
type Props = { content: string, filename: string };
|
||||
|
||||
export default function Faq({content}: Props) {
|
||||
if (!FILENAME) throw new Error('Could not determine filename');
|
||||
return <MarkdownPage content={content} filename={FILENAME}></MarkdownPage>
|
||||
export default function Page({content, filename}: Props) {
|
||||
if (!filename) throw new Error('Could not determine filename');
|
||||
return <MarkdownPage content={content} filename={filename}></MarkdownPage>
|
||||
}
|
||||
|
||||
@@ -3,10 +3,16 @@ import {SEO} from 'web/components/SEO'
|
||||
import Link from 'next/link'
|
||||
import {Col} from 'web/components/layout/col'
|
||||
import {Row} from 'web/components/layout/row'
|
||||
import React from "react";
|
||||
|
||||
export default function HelpPage() {
|
||||
return (
|
||||
<PageBase trackPageView={'help'} className={'relative p-2 sm:pt-0'}>
|
||||
<SEO
|
||||
title={'Help'}
|
||||
description={'Help and support for Compass'}
|
||||
url={`/help`}
|
||||
/>
|
||||
<SEO title={`Help`} description={'Get help with Compass'} url={`/help`}/>
|
||||
<Col className="max-w-3xl w-full mx-auto gap-6 custom-link">
|
||||
<h1 className="text-3xl font-semibold">Help & Support</h1>
|
||||
|
||||
@@ -3,6 +3,7 @@ import {Col} from 'web/components/layout/col'
|
||||
import {useUser} from 'web/hooks/use-user'
|
||||
import {LoggedOutHome} from "web/components/home/home";
|
||||
import {ProfilesHome} from "web/components/profiles/profiles-home";
|
||||
import React from "react";
|
||||
|
||||
|
||||
export default function ProfilesPage() {
|
||||
|
||||
@@ -8,12 +8,12 @@ const FILENAME = __filename.split('/').pop()?.split('.').shift();
|
||||
export async function getStaticProps() {
|
||||
const filePath = path.join(process.cwd(), 'public', 'md', FILENAME + '.md');
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
return {props: {content}};
|
||||
return {props: {content, filename: FILENAME}};
|
||||
}
|
||||
|
||||
type Props = { content: string };
|
||||
type Props = { content: string, filename: string };
|
||||
|
||||
export default function Faq({content}: Props) {
|
||||
if (!FILENAME) throw new Error('Could not determine filename');
|
||||
return <MarkdownPage content={content} filename={FILENAME}></MarkdownPage>
|
||||
export default function Page({content, filename}: Props) {
|
||||
if (!filename) throw new Error('Could not determine filename');
|
||||
return <MarkdownPage content={content} filename={filename}></MarkdownPage>
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import {useRouter} from 'next/router'
|
||||
import {usePrivateMessages, useSortedPrivateMessageMemberships,} from 'web/hooks/use-private-messages'
|
||||
import {Col} from 'web/components/layout/col'
|
||||
import {User} from 'common/user'
|
||||
import {useEffect, useState} from 'react'
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import {track} from 'web/lib/service/analytics'
|
||||
import {firebaseLogin} from 'web/lib/firebase/users'
|
||||
import {uniq} from 'lodash'
|
||||
@@ -32,6 +32,7 @@ import {useGroupedMessages, usePaginatedScrollingMessages,} from 'web/lib/supaba
|
||||
import {PrivateMessageChannel} from 'common/supabase/private-messages'
|
||||
import {ChatMessage} from 'common/chat-message'
|
||||
import {BackButton} from 'web/components/back-button'
|
||||
import {SEO} from "web/components/SEO";
|
||||
|
||||
export default function PrivateMessagesPage() {
|
||||
const router = useRouter()
|
||||
@@ -44,6 +45,11 @@ export default function PrivateMessagesPage() {
|
||||
}
|
||||
return (
|
||||
<PageBase trackPageView={'private messages page'}>
|
||||
<SEO
|
||||
title={'Messages'}
|
||||
description={'Messages'}
|
||||
url={`/messages/${channelIdString}`}
|
||||
/>
|
||||
{router.isReady && channelId && user ? (
|
||||
<PrivateMessagesContent user={user} channelId={channelId}/>
|
||||
) : (
|
||||
|
||||
@@ -19,6 +19,8 @@ import { useRedirectIfSignedOut } from 'web/hooks/use-redirect-if-signed-out'
|
||||
import { MultipleOrSingleAvatars } from 'web/components/multiple-or-single-avatars'
|
||||
import { BannedBadge } from 'web/components/widgets/user-link'
|
||||
import { PrivateMessageChannel } from 'common/supabase/private-messages'
|
||||
import {SEO} from "web/components/SEO";
|
||||
import React from "react";
|
||||
|
||||
export default function MessagesPage() {
|
||||
useRedirectIfSignedOut()
|
||||
@@ -26,6 +28,11 @@ export default function MessagesPage() {
|
||||
const currentUser = useUser()
|
||||
return (
|
||||
<PageBase trackPageView={'messages page'} className={'p-2'}>
|
||||
<SEO
|
||||
title={'Messages'}
|
||||
description={'Your Messages'}
|
||||
url={`/messages`}
|
||||
/>
|
||||
{currentUser && <MessagesContent currentUser={currentUser} />}
|
||||
</PageBase>
|
||||
)
|
||||
|
||||
@@ -2,11 +2,18 @@ import {PageBase} from 'web/components/page-base'
|
||||
import {GeneralButton} from "web/components/buttons/general-button";
|
||||
import clsx from "clsx";
|
||||
import {Col} from "web/components/layout/col";
|
||||
import {SEO} from "web/components/SEO";
|
||||
import React from "react";
|
||||
|
||||
|
||||
export default function Organization() {
|
||||
return (
|
||||
<PageBase trackPageView={'social'}>
|
||||
<SEO
|
||||
title={'Organization'}
|
||||
description={'Organization'}
|
||||
url={`/organization`}
|
||||
/>
|
||||
<h3 className="text-4xl font-bold text-center mt-8 mb-8">Organization</h3>
|
||||
<Col
|
||||
className={clsx(
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import {PageBase} from "web/components/page-base";
|
||||
import {supportEmail} from "common/constants";
|
||||
import {SEO} from "web/components/SEO";
|
||||
import React from "react";
|
||||
|
||||
// TODO: convert to MarkDown for better readability during modifications?
|
||||
export default function PrivacyPage() {
|
||||
@@ -8,6 +10,11 @@ export default function PrivacyPage() {
|
||||
trackPageView={'terms'}
|
||||
className="max-w-4xl mx-auto p-8 col-span-8 bg-canvas-0"
|
||||
>
|
||||
<SEO
|
||||
title={'Privacy'}
|
||||
description={'Privacy Policy for Compass'}
|
||||
url={`/privacy`}
|
||||
/>
|
||||
<h1 className="text-3xl font-semibold text-center mb-6">Privacy Policy</h1>
|
||||
|
||||
<p className="text-center mb-12">
|
||||
|
||||
@@ -5,11 +5,12 @@ import {OptionalProfileUserForm} from 'web/components/optional-profile-form'
|
||||
import {RequiredProfileUserForm} from 'web/components/required-profile-form'
|
||||
import {useProfileByUser} from 'web/hooks/use-profile'
|
||||
import Router from 'next/router'
|
||||
import {useEffect, useState} from 'react'
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import {Col} from 'web/components/layout/col'
|
||||
import {useUser} from 'web/hooks/use-user'
|
||||
import {api} from 'web/lib/api'
|
||||
import {PageBase} from "web/components/page-base";
|
||||
import {SEO} from "web/components/SEO";
|
||||
|
||||
export default function ProfilePage() {
|
||||
const user = useUser()
|
||||
@@ -41,6 +42,11 @@ function ProfilePageInner(props: { user: User; profile: Profile }) {
|
||||
|
||||
return (
|
||||
<PageBase trackPageView={'profile'}>
|
||||
<SEO
|
||||
title={'Profile'}
|
||||
description={'Your Profile'}
|
||||
url={`/profile`}
|
||||
/>
|
||||
<Col className="items-center">
|
||||
<Col className={'w-full px-6 py-4'}>
|
||||
<RequiredProfileUserForm
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import {Suspense, useEffect, useState} from "react";
|
||||
import React, {Suspense, useEffect, useState} from "react";
|
||||
import Link from "next/link";
|
||||
import {useSearchParams} from "next/navigation";
|
||||
import {signupThenMaybeRedirectToSignup} from "web/lib/util/signup";
|
||||
@@ -14,6 +14,7 @@ import {db} from "web/lib/supabase/db";
|
||||
import Router from "next/router";
|
||||
import {useUser} from "web/hooks/use-user";
|
||||
import {GoogleButton} from "web/components/buttons/sign-up-button";
|
||||
import {SEO} from "web/components/SEO";
|
||||
|
||||
|
||||
export default function RegisterPage() {
|
||||
@@ -111,6 +112,11 @@ function RegisterComponent() {
|
||||
|
||||
return (
|
||||
<PageBase trackPageView={'register'}>
|
||||
<SEO
|
||||
title={'Register'}
|
||||
description={'Register for a new account'}
|
||||
url={`/register`}
|
||||
/>
|
||||
<div className="min-h-screen flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div className="max-w-md w-full space-y-8">
|
||||
{registrationSuccess ? (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import {useSearchParams} from "next/navigation";
|
||||
import {Suspense, useEffect, useState} from "react";
|
||||
import React, {Suspense, useEffect, useState} from "react";
|
||||
import Link from "next/link";
|
||||
import {auth, firebaseLogin} from "web/lib/firebase/users";
|
||||
import FavIcon from "web/public/FavIcon";
|
||||
@@ -13,6 +13,7 @@ import Router from "next/router";
|
||||
import {PageBase} from "web/components/page-base";
|
||||
import {useUser} from "web/hooks/use-user";
|
||||
import {GoogleButton} from "web/components/buttons/sign-up-button";
|
||||
import {SEO} from "web/components/SEO";
|
||||
|
||||
export default function LoginPage() {
|
||||
return (
|
||||
@@ -118,6 +119,11 @@ function RegisterComponent() {
|
||||
console.debug('Form rendering');
|
||||
return (
|
||||
<PageBase trackPageView={'signin'}>
|
||||
<SEO
|
||||
title={'Sign In'}
|
||||
description={'Sign in to your account'}
|
||||
url={`/signin`}
|
||||
/>
|
||||
<div className="min-h-screen flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div className="max-w-md w-full space-y-8">
|
||||
<div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {useEffect, useRef, useState} from 'react'
|
||||
import React, {useEffect, useRef, useState} from 'react'
|
||||
import {Col} from 'web/components/layout/col'
|
||||
import {initialRequiredState, RequiredProfileUserForm,} from 'web/components/required-profile-form'
|
||||
import {OptionalProfileUserForm} from 'web/components/optional-profile-form'
|
||||
@@ -14,6 +14,7 @@ import {removeNullOrUndefinedProps} from 'common/util/object'
|
||||
import {useProfileByUserId} from 'web/hooks/use-profile'
|
||||
import {ProfileRow} from 'common/profiles/profile'
|
||||
import {PageBase} from "web/components/page-base";
|
||||
import {SEO} from "web/components/SEO";
|
||||
|
||||
export default function SignupPage() {
|
||||
const [step, setStep] = useState(0)
|
||||
@@ -72,6 +73,11 @@ export default function SignupPage() {
|
||||
|
||||
if (step === 1 && user) {
|
||||
return <PageBase trackPageView={'register'}>
|
||||
<SEO
|
||||
title={'Sign Up'}
|
||||
description={'Sign Up to Compass'}
|
||||
url={`/signup`}
|
||||
/>
|
||||
<Col className={'w-full px-6 py-4'}>
|
||||
<OptionalProfileUserForm
|
||||
setProfile={setProfileState}
|
||||
|
||||
@@ -3,11 +3,18 @@ import {discordLink, githubRepo, redditLink, stoatLink, supportEmail, xLink} fro
|
||||
import {GeneralButton} from "web/components/buttons/general-button";
|
||||
import clsx from "clsx";
|
||||
import {Col} from "web/components/layout/col";
|
||||
import {SEO} from "web/components/SEO";
|
||||
import React from "react";
|
||||
|
||||
|
||||
export default function Social() {
|
||||
return (
|
||||
<PageBase trackPageView={'social'}>
|
||||
<SEO
|
||||
title={'Socials'}
|
||||
description={'Socials'}
|
||||
url={`/social`}
|
||||
/>
|
||||
<h3 className="text-4xl font-bold text-center mt-8 mb-8">Socials</h3>
|
||||
<Col
|
||||
className={clsx(
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import {PageBase} from "web/components/page-base";
|
||||
import ChartMembers from "web/components/widgets/charts";
|
||||
import {getCount} from "web/lib/supabase/users";
|
||||
import {useEffect, useState} from "react";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import StatBox from "web/components/widgets/stat-box";
|
||||
import clsx from "clsx";
|
||||
import {Col} from "web/components/layout/col";
|
||||
import {SEO} from "web/components/SEO";
|
||||
|
||||
export default function Stats() {
|
||||
const [data, setData] = useState<Record<string, number | null>>({})
|
||||
@@ -42,7 +43,12 @@ export default function Stats() {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<PageBase trackPageView={'charts'}>
|
||||
<PageBase trackPageView={'stats'}>
|
||||
<SEO
|
||||
title={'Stats'}
|
||||
description={'Stats'}
|
||||
url={`/stats`}
|
||||
/>
|
||||
<h1 className="text-3xl font-semibold text-center mb-6">Growth & Stats</h1>
|
||||
<Col className={'sm:mx-4 mx-1 mb-8'}>
|
||||
<ChartMembers/>
|
||||
|
||||
@@ -8,12 +8,12 @@ const FILENAME = __filename.split('/').pop()?.split('.').shift();
|
||||
export async function getStaticProps() {
|
||||
const filePath = path.join(process.cwd(), 'public', 'md', FILENAME + '.md');
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
return {props: {content}};
|
||||
return {props: {content, filename: FILENAME}};
|
||||
}
|
||||
|
||||
type Props = { content: string };
|
||||
type Props = { content: string, filename: string };
|
||||
|
||||
export default function Faq({content}: Props) {
|
||||
if (!FILENAME) throw new Error('Could not determine filename');
|
||||
return <MarkdownPage content={content} filename={FILENAME}></MarkdownPage>
|
||||
}
|
||||
export default function Page({content, filename}: Props) {
|
||||
if (!filename) throw new Error('Could not determine filename');
|
||||
return <MarkdownPage content={content} filename={filename}></MarkdownPage>
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
import {PageBase} from "web/components/page-base";
|
||||
import {supportEmail} from "common/constants";
|
||||
import {SEO} from "web/components/SEO";
|
||||
import React from "react";
|
||||
|
||||
// TODO: convert to MarkDown for better readability during modifications?
|
||||
export default function TermsPage() {
|
||||
@@ -8,6 +10,11 @@ export default function TermsPage() {
|
||||
trackPageView={'terms'}
|
||||
className="max-w-4xl mx-auto p-8 text-gray-800 dark:text-white col-span-8 bg-canvas-0"
|
||||
>
|
||||
<SEO
|
||||
title={'Terms & Conditions'}
|
||||
description={'Terms & Conditions for Compass'}
|
||||
url={`/terms`}
|
||||
/>
|
||||
<h1 className="text-3xl font-semibold text-center mb-6">Terms & Conditions</h1>
|
||||
|
||||
<p className="text-center text-gray-500 dark:text-white mb-12">
|
||||
|
||||
@@ -8,12 +8,12 @@ const FILENAME = __filename.split('/').pop()?.split('.').shift();
|
||||
export async function getStaticProps() {
|
||||
const filePath = path.join(process.cwd(), 'public', 'md', FILENAME + '.md');
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
return {props: {content}};
|
||||
return {props: {content, filename: FILENAME}};
|
||||
}
|
||||
|
||||
type Props = { content: string };
|
||||
type Props = { content: string, filename: string };
|
||||
|
||||
export default function Faq({content}: Props) {
|
||||
if (!FILENAME) throw new Error('Could not determine filename');
|
||||
return <MarkdownPage content={content} filename={FILENAME}></MarkdownPage>
|
||||
}
|
||||
export default function Page({content, filename}: Props) {
|
||||
if (!filename) throw new Error('Could not determine filename');
|
||||
return <MarkdownPage content={content} filename={filename}></MarkdownPage>
|
||||
}
|
||||
Reference in New Issue
Block a user