Skip to content
Zutra HyperSaaS — 6 languages, auth UI, dashboard, 69 tests
Get it on Gumroad

Zutra v1.3.0 — 6 languages, auth UI, dashboard, 69 tests. Saves 80+ hours.

See what's included

Customization

How to change colors, fonts, copy, layout, and branding — without breaking the design system.

The customization order

When you fork Zutra, change things in this order:

  1. src/config/site.ts — name, tagline, URL, social handles
  2. src/config/features.ts — what shows on the features section
  3. src/config/pricing.ts — your plan tiers and copy
  4. src/config/hero.ts — hero copy, simulator metrics
  5. src/config/nav.ts — top nav links
  6. src/styles/global.css — colors, fonts, radii (only if needed)
  7. Components — last resort, only for layout-level changes

Most customisations need only steps 1–5.

Site identity

src/config/site.ts:

export const SITE = {
  name:           'Your SaaS',
  tagline:        'The tagline that sells.',
  description:    'Longer description for SEO meta tags.',
  url:            SITE_URL,           // edit in src/site.ts
  appUrl:         'https://app.yourdomain.com',
  twitterHandle:  '@yourhandle',
  ogImage:        '/og/home.svg',
  themeColor:     '#000000',
};

SITE_URL comes from src/site.ts — it’s also pulled into astro.config.mjs for sitemap and OG generation.

The Logo component (src/components/Logo.astro) supports three modes:

export const LOGO = {
  type:     'icon+text',   // 'icon+text' | 'image' | 'text'
  iconSrc:  '/logo-icon.svg',
  imageSrc: '/logo.svg',
  imageAlt: SITE.name,
};
  • icon+text — small mark + name (default)
  • image — full wordmark image, replaces everything
  • text — name only, no icon

Replace public/logo.svg and public/logo-icon.svg with your brand assets. Keep them under 5KB for fast LCP.

Hero copy

src/config/hero.ts:

export const HERO = {
  badge:         'Early Access',
  headline:      '...',                  // actually comes from i18n (translatable)
  subline:       'Ship production-grade SaaS in days — not months.',
  socialProof: {
    label:     'Trusted by engineers at',
    companies: ['Vercel', 'Linear', 'Stripe', 'Railway'],
  },
};

The headline itself is pulled from src/i18n/en/hero.json (hero.headline) — this is what makes it translatable. Update both en/hero.json and es/hero.json.

The simulator window (the mock UI on the right of the hero) reads from HERO.simulator.metrics, .logs, .deploySteps, and .team. Edit those to match your actual product story.

Pricing

src/config/pricing.ts — see the Configuration Reference for the full shape. Common edits:

  • Add a plan — append to the PRICING array
  • Change a price — update monthlyPrice / annualPrice
  • Change a feature — edit the features array (each item has text and included: boolean)
  • Highlight a plan — set highlighted: true (only one at a time)

The pricing UI (PricingCard.astro) reads from this config and renders everything — there’s nothing to edit in the component.

src/config/nav.ts:

export const NAV = {
  links: [
    { href: '/features', label: 'Features' },
    { href: '/pricing',  label: 'Pricing'  },
    { href: '/docs',     label: 'Docs'     },
    { href: '/changelog', label: 'Changelog' },
    { href: '/customers', label: 'Customers' },
    { href: '/blog',     label: 'Blog'     },
  ],
  dropdown: [
    { href: '/dashboard', label: 'Dashboard' },
    { href: '/about',     label: 'About'     },
    // ...
  ],
  cta: {
    label: 'Get the template',
    href:  'https://your-purchase-link.com',
  },
};

The dropdown appears as “Pages ▾” in the desktop nav. To hide it before launch, set FEATURE_FLAGS.demoDropdown: false in src/config/features.ts.

Colors

For most projects, you don’t need to touch the colors — pick an accent via the ThemePicker. But if you want a single brand color baked in:

  1. Set FEATURE_FLAGS.themePicker: false in src/config/features.ts
  2. Edit the :root block at the top of src/styles/global.css:
:root {
  --accent:       #your-brand-color;
  --accent-hover: #lighter-shade;
  --accent-fg:    #ffffff;  /* foreground color on accent backgrounds */
}

For more invasive changes (full rebrand), edit the @theme block:

@theme {
  --color-void:     #000000;
  --color-deep:     #your-deep;
  --color-surface:  #your-surface;
  --color-elevated: #your-elevated;
  --color-text-primary: #your-text;
  /* ... */
}

Fonts

src/styles/global.css imports fonts via @fontsource:

@import "@fontsource/inter/400.css";
@import "@fontsource/inter/500.css";
@import "@fontsource/inter/600.css";
@import "@fontsource/inter/700.css";

To switch to a different family:

pnpm add @fontsource/your-font

Then edit global.css and the --font-family-sans token in @theme.

Monospace uses "Berkeley Mono", with "JetBrains Mono" and "Fira Code" as fallbacks. To swap, edit --font-family-mono in @theme.

Layout changes

If you need to change the layout of an existing section — for example, switching the features grid from 3 columns to 4 — open the component (src/components/home/FeaturesSection.astro) and edit the grid classes.

If you need to add a new section to a page:

  1. Create a new component under the relevant feature directory (src/components/home/)
  2. Import it in the page (src/pages/index.astro)
  3. Place it in the right vertical order

If you need to remove a section, delete the import + usage in the page file. Don’t delete the component itself unless you’re sure no other page uses it.

Animations & micro-interactions

The template uses three sources of motion:

  1. Tailwind transitionstransition-colors duration-150, hover:bg-..., etc.
  2. <style> blocks — for keyframes (.fadeIn, .pulse-ring)
  3. CSS view transitions — Astro’s built-in page-transition system

If you disable animations globally (for accessibility), the @media (prefers-reduced-motion: reduce) block at the bottom of global.css already does this.

Next steps