diff --git a/web/scripts/generate-sitemap.js b/web/scripts/generate-sitemap.js index 08c8a78..dd77d85 100644 --- a/web/scripts/generate-sitemap.js +++ b/web/scripts/generate-sitemap.js @@ -29,6 +29,7 @@ const STATIC_PATHS = [ "/open-source-seo", "/google-search-console-mcp", "/roadmap", + "/support", ...Object.values(FEATURE_PAGE_SLUGS).map((slug) => `/features/${slug}`), ]; diff --git a/web/src/components/site-footer.tsx b/web/src/components/site-footer.tsx index b094835..9447658 100644 --- a/web/src/components/site-footer.tsx +++ b/web/src/components/site-footer.tsx @@ -60,6 +60,7 @@ export function SiteFooter({ className }: { className?: string }) {

Company

+ Support Roadmap Pricing rootRouteImport, } as any) +const MarketingSupportRoute = MarketingSupportRouteImport.update({ + id: '/support', + path: '/support', + getParentRoute: () => MarketingRoute, +} as any) const MarketingRoadmapRoute = MarketingRoadmapRouteImport.update({ id: '/roadmap', path: '/roadmap', @@ -318,6 +324,7 @@ export interface FileRoutesByFullPath { '/open-source-seo': typeof MarketingOpenSourceSeoRoute '/pricing': typeof MarketingPricingRoute '/roadmap': typeof MarketingRoadmapRoute + '/support': typeof MarketingSupportRoute '/api/backlink-check': typeof ApiBacklinkCheckRoute '/api/event': typeof ApiEventRoute '/api/subscribe': typeof ApiSubscribeRoute @@ -363,6 +370,7 @@ export interface FileRoutesByTo { '/open-source-seo': typeof MarketingOpenSourceSeoRoute '/pricing': typeof MarketingPricingRoute '/roadmap': typeof MarketingRoadmapRoute + '/support': typeof MarketingSupportRoute '/api/backlink-check': typeof ApiBacklinkCheckRoute '/api/event': typeof ApiEventRoute '/api/subscribe': typeof ApiSubscribeRoute @@ -411,6 +419,7 @@ export interface FileRoutesById { '/_marketing/open-source-seo': typeof MarketingOpenSourceSeoRoute '/_marketing/pricing': typeof MarketingPricingRoute '/_marketing/roadmap': typeof MarketingRoadmapRoute + '/_marketing/support': typeof MarketingSupportRoute '/api/backlink-check': typeof ApiBacklinkCheckRoute '/api/event': typeof ApiEventRoute '/api/subscribe': typeof ApiSubscribeRoute @@ -460,6 +469,7 @@ export interface FileRouteTypes { | '/open-source-seo' | '/pricing' | '/roadmap' + | '/support' | '/api/backlink-check' | '/api/event' | '/api/subscribe' @@ -505,6 +515,7 @@ export interface FileRouteTypes { | '/open-source-seo' | '/pricing' | '/roadmap' + | '/support' | '/api/backlink-check' | '/api/event' | '/api/subscribe' @@ -552,6 +563,7 @@ export interface FileRouteTypes { | '/_marketing/open-source-seo' | '/_marketing/pricing' | '/_marketing/roadmap' + | '/_marketing/support' | '/api/backlink-check' | '/api/event' | '/api/subscribe' @@ -707,6 +719,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ApiBacklinkCheckRouteImport parentRoute: typeof rootRouteImport } + '/_marketing/support': { + id: '/_marketing/support' + path: '/support' + fullPath: '/support' + preLoaderRoute: typeof MarketingSupportRouteImport + parentRoute: typeof MarketingRoute + } '/_marketing/roadmap': { id: '/_marketing/roadmap' path: '/roadmap' @@ -933,6 +952,7 @@ interface MarketingRouteChildren { MarketingOpenSourceSeoRoute: typeof MarketingOpenSourceSeoRoute MarketingPricingRoute: typeof MarketingPricingRoute MarketingRoadmapRoute: typeof MarketingRoadmapRoute + MarketingSupportRoute: typeof MarketingSupportRoute MarketingIndexRoute: typeof MarketingIndexRoute MarketingFeaturesAiBrandVisibilityRoute: typeof MarketingFeaturesAiBrandVisibilityRoute MarketingFeaturesAiSearchPromptsRoute: typeof MarketingFeaturesAiSearchPromptsRoute @@ -968,6 +988,7 @@ const MarketingRouteChildren: MarketingRouteChildren = { MarketingOpenSourceSeoRoute: MarketingOpenSourceSeoRoute, MarketingPricingRoute: MarketingPricingRoute, MarketingRoadmapRoute: MarketingRoadmapRoute, + MarketingSupportRoute: MarketingSupportRoute, MarketingIndexRoute: MarketingIndexRoute, MarketingFeaturesAiBrandVisibilityRoute: MarketingFeaturesAiBrandVisibilityRoute, diff --git a/web/src/routes/_marketing/support.tsx b/web/src/routes/_marketing/support.tsx new file mode 100644 index 0000000..5ad861f --- /dev/null +++ b/web/src/routes/_marketing/support.tsx @@ -0,0 +1,163 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { useState } from "react"; +import { buildPageSeo } from "@/lib/seo"; + +const SUPPORT_EMAIL = "ben@openseo.so"; +const DISCORD_URL = "https://discord.gg/c9uGs3cFXr"; +const GITHUB_ISSUES_URL = "https://github.com/every-app/open-seo/issues"; + +export const Route = createFileRoute("/_marketing/support")({ + head: () => + buildPageSeo({ + title: "Support", + description: + "Get help with OpenSEO, share feedback, or report an issue by email, Discord, or GitHub.", + path: "/support", + titleSuffix: "OpenSEO", + }), + component: SupportPage, +}); + +function SupportPage() { + const [copied, setCopied] = useState(false); + + async function copyEmail() { + await navigator.clipboard.writeText(SUPPORT_EMAIL); + setCopied(true); + window.setTimeout(() => setCopied(false), 2000); + } + + return ( +
+
+

+ Help & Community +

+

+ We want to hear from you +

+

+ We want to talk to you! We're super open to feedback and want to + learn how you work so we can make OpenSEO better. +

+
+ +
+
+

+ 01 +

+

+ Email +

+

+ Send ideas, problems, questions, or feedback directly. +

+ +
+ + + + +
+
+ ); +} + +function SupportCard({ + number, + title, + description, + href, + linkText, +}: { + number: string; + title: string; + description: string; + href: string; + linkText: string; +}) { + return ( +
+

+ {number} +

+

+ {title} +

+

+ {description} +

+ + {linkText} + + +
+ ); +} + +function CopyIcon() { + return ( + + ); +} + +function CheckIcon() { + return ( + + ); +}