diff --git a/apps/marketing/next.config.ts b/apps/marketing/next.config.ts index b6718d660..ff954da6b 100644 --- a/apps/marketing/next.config.ts +++ b/apps/marketing/next.config.ts @@ -56,6 +56,11 @@ const config: NextConfig = { destination: "/examples/infrastructure", permanent: true, }, + { + source: "/examples/:framework(react|vue|angular|svelte|solid|vanilla)/:example", + destination: "/examples/:example", + permanent: true, + }, { source: "/examples", destination: "/examples/crm", diff --git a/apps/marketing/src/app/case-studies/chartmetric/page.tsx b/apps/marketing/src/app/case-studies/chartmetric/page.tsx index 802724a27..c1cefa419 100644 --- a/apps/marketing/src/app/case-studies/chartmetric/page.tsx +++ b/apps/marketing/src/app/case-studies/chartmetric/page.tsx @@ -114,7 +114,7 @@ export default function ChartMetricCaseStudyPage() {
-
99%
+
100%
Customization needs met
@@ -214,7 +214,7 @@ export default function ChartMetricCaseStudyPage() {

Simple Table was highly customizable—around{" "} - 99% of our needs were covered through built-in customization + 100% of our needs were covered through built-in customization options such as CSS variable overrides,{" "} custom icons, and custom headers. For edge cases, we were able to rely on global class selectors. diff --git a/apps/marketing/src/app/examples/[framework]/[example]/page.tsx b/apps/marketing/src/app/examples/[framework]/[example]/page.tsx deleted file mode 100644 index 768e2aed2..000000000 --- a/apps/marketing/src/app/examples/[framework]/[example]/page.tsx +++ /dev/null @@ -1,215 +0,0 @@ -import type { Metadata } from "next"; -import Link from "next/link"; -import { notFound } from "next/navigation"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faBox, faCode, faRocket, faTerminal } from "@fortawesome/free-solid-svg-icons"; -import { - EXAMPLE_SLUGS, - FRAMEWORK_HUB_BY_ID, - FRAMEWORK_HUB_IDS, - type ExampleSlug, - type HubFrameworkId, -} from "@/constants/frameworkIntegrationHub"; -import { FRAMEWORK_INSTALL_COMMANDS } from "@/constants/strings/technical"; -import { SEO_STRINGS } from "@/constants/strings/seo"; -import { getStackBlitzUrl } from "@/utils/getStackBlitzUrl"; -import type { Framework } from "@/providers/FrameworkProvider"; -import BlogLayout from "@/components/BlogLayout"; - -type PageProps = { params: Promise<{ framework: string; example: string }> }; - -export function generateStaticParams() { - return FRAMEWORK_HUB_IDS.flatMap((framework) => - EXAMPLE_SLUGS.map((example) => ({ framework, example })) - ); -} - -function isHubId(value: string): value is HubFrameworkId { - return FRAMEWORK_HUB_IDS.includes(value as HubFrameworkId); -} - -function isExampleSlug(value: string): value is ExampleSlug { - return EXAMPLE_SLUGS.includes(value as ExampleSlug); -} - -const EXAMPLE_LABELS: Record = { - billing: "Billing & invoicing", - crm: "CRM leads management", - hr: "HR management", - infrastructure: "Infrastructure monitoring", - manufacturing: "Manufacturing dashboard", - music: "Music artist analytics", - sales: "Sales pipeline", -}; - -export async function generateMetadata({ params }: PageProps): Promise { - const { framework: rawFw, example: rawEx } = await params; - if (!isHubId(rawFw) || !isExampleSlug(rawEx)) { - return { title: "Example" }; - } - const fw = FRAMEWORK_HUB_BY_ID[rawFw]; - const exampleLabel = EXAMPLE_LABELS[rawEx]; - const baseSeo = SEO_STRINGS.examples[rawEx]; - const title = `${exampleLabel} for ${fw.label} | Simple Table`; - const description = `Build a ${exampleLabel.toLowerCase()} data grid with Simple Table on ${fw.label}. Install ${fw.npmPackage}, copy the idiomatic snippet, and run the live demo in StackBlitz. ${baseSeo.description}`; - const lower = fw.label.toLowerCase(); - return { - title, - description, - keywords: [ - `${lower} ${rawEx} table`, - `${lower} ${rawEx} data grid`, - `${lower} data grid example`, - `${rawEx} dashboard ${lower}`, - "simple-table", - fw.npmPackage, - ], - openGraph: { - title, - description, - type: "article", - images: [SEO_STRINGS.site.ogImage], - siteName: SEO_STRINGS.site.name, - }, - twitter: { - card: "summary_large_image", - title, - description, - creator: SEO_STRINGS.site.creator, - images: SEO_STRINGS.site.ogImage.url, - }, - alternates: { canonical: `/examples/${rawFw}/${rawEx}` }, - }; -} - -export default async function FrameworkExamplePage({ params }: PageProps) { - const { framework: rawFw, example: rawEx } = await params; - if (!isHubId(rawFw) || !isExampleSlug(rawEx)) notFound(); - const fw = FRAMEWORK_HUB_BY_ID[rawFw]; - const exampleLabel = EXAMPLE_LABELS[rawEx]; - const installCmd = FRAMEWORK_INSTALL_COMMANDS[rawFw as Framework]?.npm ?? `npm install ${fw.installPackages}`; - const stackBlitzUrl = getStackBlitzUrl(rawEx, rawFw as Framework); - const stackBlitzEmbedUrl = `${stackBlitzUrl}?embed=1&hideExplorer=1&hideNavigation=1&view=preview`; - - return ( - -

- -
-

- {exampleLabel} on {fw.label} -

-

- A real {exampleLabel.toLowerCase()} data grid built with Simple Table on {fw.label}. Install{" "} - - {fw.npmPackage} - - , copy the idiomatic snippet below, and open the live, editable demo in StackBlitz. -

-
- -
-
-

- - Install -

-

- Peer expectations: {fw.peerSummary} -

-
-            {installCmd}
-          
-
- -
-

- - Idiomatic {fw.label} usage -

-
-            {fw.minimalSnippet}
-          
-

- {fw.label} stylesheet import:{" "} - - {fw.stylesImport} - -

-
- -
-

- - Live, editable demo -

-

- The full {exampleLabel.toLowerCase()} data grid runs below as a {fw.label} project on - StackBlitz. Edit the code in-place, save, or fork it into your own workspace. -

-
-