LogoMkSaaS Docs

Custom Pages

Learn how to customize and create new pages in your MkSaaS website

This guide covers the page system in your MkSaaS website, how to customize existing pages, and how to create new pages for your specific needs.

Core Features

The MkSaaS template includes a versatile content management system that allows you to:

  • Customize legal pages (Cookie Policy, Privacy Policy, Terms of Service)
  • Maintain changelog entries for version releases
  • Create marketing and informational pages (About, Contact, Waitlist)
  • Add completely custom pages for your specific needs

Page Structure

Pages in MkSaaS are organized into different categories:

Legal pages are stored in the content/pages directory and rendered in the src/app/[locale]/(marketing)/(legal) routes:

  • Cookie Policy: Information about how your website uses cookies
  • Privacy Policy: Details about how you handle user data
  • Terms of Service: Rules and regulations for using your service

Changelog Entries

Release notes are stored in the content/release directory and displayed on the Changelog page:

  • Version Releases: Each release has its own MDX file with version details and changes

Marketing Pages

Marketing pages are rendered in the src/app/[locale]/(marketing)/(pages) routes:

  • About: Information about your company or project
  • Contact: Contact forms and information
  • Waitlist: Registration for early access or notifications
  • Changelog: Page displaying all release notes

Customizing Existing Pages

Legal pages are written in MDX format and located in the content/pages directory. Each file includes frontmatter metadata and the content body.

Example: Privacy Policy (privacy-policy.mdx)

content/pages/privacy-policy.mdx
---
title: Privacy Policy
description: Our commitment to protecting your privacy and personal data
date: 2025-03-10T00:00:00.000Z
published: true
---
 
## Introduction
 
Welcome to our Privacy Policy. This document explains how we collect, use, and protect your personal information when you use our services.
 
... more content ...

To customize a legal page:

  1. Open the corresponding MDX file in the content/pages directory
  2. Update the frontmatter metadata (title, description, date)
  3. Modify the content in Markdown format
  4. Save the file

The page will automatically update with your changes.

Changelog Entries

Changelog entries are stored as MDX files in the content/release directory.

Example: Release v1.0.0 (v1-0-0.mdx)

content/release/v1-0-0.mdx
---
title: "Initial Release"
description: "Our first official release with core features and functionality"
date: "2024-03-01T00:00:00Z"
version: "v1.0.0"
published: true
---
 
### Core Features
 
We're excited to announce the initial release of our platform with the following core features:
 
- **User Authentication**: Secure login and registration with email verification
- **Dashboard**: Intuitive dashboard for managing your projects and resources
 
... more content ...

To add a new release:

  1. Create a new MDX file in the content/release directory (e.g., v1-1-0.mdx)
  2. Add the appropriate frontmatter metadata (title, description, date, version, published)
  3. Write the release notes using Markdown
  4. Save the file

The new release will automatically appear on your Changelog page, sorted by date (newest first).

Creating New Pages

You can create completely custom pages for your specific needs. There are two approaches:

1. MDX-Based Pages

For content-heavy pages that don't require complex interactivity:

  1. Create a new MDX file in the content/pages directory (e.g., faq.mdx)
  2. Add the appropriate frontmatter metadata
  3. Write your content in Markdown format
  4. Create a new page component in src/app/[locale]/(marketing)/(pages)/faq/page.tsx

Here's a template for the page component:

import { CustomPage } from '@/components/page/custom-page';
import { constructMetadata } from '@/lib/metadata';
import { getPage } from '@/lib/page/get-page';
import { getUrlWithLocale } from '@/lib/urls/urls';
import type { NextPageProps } from '@/types/next-page-props';
import type { Metadata } from 'next';
import type { Locale } from 'next-intl';
import { getTranslations } from 'next-intl/server';
import { notFound } from 'next/navigation';
 
export async function generateMetadata({
  params,
}: {
  params: Promise<{ locale: Locale }>;
}): Promise<Metadata | undefined> {
  const { locale } = await params;
  const page = await getPage('faq', locale);
 
  if (!page) {
    return {};
  }
 
  const t = await getTranslations({ locale, namespace: 'Metadata' });
 
  return constructMetadata({
    title: page.title + ' | ' + t('title'),
    description: page.description,
    canonicalUrl: getUrlWithLocale('/faq', locale),
  });
}
 
export default async function FAQPage(props: NextPageProps) {
  const params = await props.params;
  if (!params) {
    notFound();
  }
 
  const locale = params.locale as string;
  const page = await getPage('faq', locale);
 
  if (!page) {
    notFound();
  }
 
  return (
    <CustomPage
      title={page.title}
      description={page.description}
      date={page.date}
      content={page.body}
    />
  );
}

2. Component-Based Pages

For pages that require more complex interactivity:

  1. Create a new directory in src/app/[locale]/(marketing)/(pages) (e.g., pricing)
  2. Add a page.tsx file that exports your custom page component

Example of a custom page component:

import { Button } from '@/components/ui/button';
import { constructMetadata } from '@/lib/metadata';
import { getUrlWithLocale } from '@/lib/urls/urls';
import type { NextPageProps } from '@/types/next-page-props';
import type { Metadata } from 'next';
import type { Locale } from 'next-intl';
import { getTranslations } from 'next-intl/server';
 
export async function generateMetadata({
  params,
}: {
  params: Promise<{ locale: Locale }>;
}): Promise<Metadata | undefined> {
  const { locale } = await params;
  const t = await getTranslations({ locale, namespace: 'Metadata' });
  const pt = await getTranslations({ locale, namespace: 'PricingPage' });
 
  return constructMetadata({
    title: pt('title') + ' | ' + t('title'),
    description: pt('description'),
    canonicalUrl: getUrlWithLocale('/pricing', locale),
  });
}
 
export default async function PricingPage(props: NextPageProps) {
  const params = await props.params;
  const locale = params?.locale as Locale;
  const t = await getTranslations('PricingPage');
 
  return (
    <div className="max-w-4xl mx-auto space-y-8">
      <div className="space-y-4">
        <h1 className="text-center text-3xl font-bold tracking-tight">
          {t('title')}
        </h1>
        <p className="text-center text-lg text-muted-foreground">
          {t('subtitle')}
        </p>
      </div>
      
      {/* Your custom pricing components */}
      <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
        {/* Pricing cards go here */}
      </div>
      
      <div className="text-center mt-12">
        <Button size="lg">{t('cta')}</Button>
      </div>
    </div>
  );
}

Custom Layouts

You can customize the layout for different page types by modifying the following files:

  • src/app/[locale]/(marketing)/(legal)/layout.tsx - For legal pages
  • src/app/[locale]/(marketing)/(pages)/layout.tsx - For marketing pages

These layout files control the container, spacing, and overall structure of the pages.

Page Routes

The page routes are defined in the src/routes.ts file. The routing system includes several important route categories that control access and navigation in your application:

Protected Routes

Protected routes require user authentication to access. If a user tries to access these routes without being logged in, they will be automatically redirected to the login page. The login page will include a callbackUrl parameter to redirect the user back to their intended destination after successful authentication.

src/routes.ts
export const protectedRoutes = [
  Routes.Dashboard,
  Routes.SettingsProfile,
  Routes.SettingsBilling,
  Routes.SettingsSecurity,
  Routes.SettingsNotifications,
];

Routes Not Allowed for Logged-in Users

These routes are specifically blocked for users who are already logged in. When an authenticated user tries to access these routes, they will be automatically redirected to the default login redirect page (typically the dashboard).

src/routes.ts
export const routesNotAllowedByLoggedInUsers = [
  Routes.Login,
  Routes.Register
];

Default Login Redirect

This route defines where users are redirected after successful login if no specific callbackUrl is provided. By default, it redirects to the dashboard, but this can be configured in your website configuration:

src/routes.ts
export const DEFAULT_LOGIN_REDIRECT = websiteConfig.routes.defaultLoginRedirect ?? Routes.Dashboard;

SEO Optimization

MkSaaS includes built-in SEO features for pages:

  1. Each page generates appropriate metadata using the generateMetadata function
  2. Canonical URLs are automatically created
  3. Page titles and descriptions are used for SEO metadata

Best Practices

  • Keep Content Updated: Regularly review and update your legal pages and documentation
  • Use Clear Structure: Organize content with proper headings and sections
  • Include Metadata: Always provide accurate title, description, and date in frontmatter
  • Optimize Images: If including images in MDX content, optimize them for web
  • Test Translations: If supporting multiple languages, test all translations
  • Mobile Responsiveness: Ensure all pages are fully responsive on mobile devices

Next Steps

Now that you understand how to work with pages in MkSaaS, explore these related topics: