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

Configuration Reference

Every option in src/config.ts explained in one place.

Overview

src/config.ts is the single file buyers edit. Components, pages, and emails read from it — nothing is hardcoded in templates.

Rule: if you find a URL, email, or label hardcoded somewhere outside config.ts, open an issue.


SITE

Basic site identity. Used in <title>, meta tags, OG images, and the sitemap.

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

SITE_URL is imported from src/site.ts. Edit it there — astro.config.mjs pulls the same value automatically.


Controls the brand mark in the nav, footer, and mobile drawer.

type What renders
'icon+text' Small SVG icon + SITE.name (default)
'image' A full image replaces everything — ideal for horizontal wordmarks
'text' SITE.name only, no icon
export const LOGO = {
  type:     'icon+text',
  iconSrc:  '/logo-icon.svg',   // used in 'icon+text' mode
  imageSrc: '/logo.svg',        // used in 'image' mode
  imageAlt: SITE.name,
}

FEATURE_FLAGS

Toggle entire features on/off without touching components.

export const FEATURE_FLAGS = {
  maintenanceMode:  false,  // redirects all routes to /maintenance
  waitlistMode:     false,  // redirects /signup and /pricing to /#waitlist
  announcementBar:  true,   // top announcement strip
  analytics:        false,  // inject analytics script on cookie consent
  demoDropdown:     true,   // "Pages ▾" nav dropdown (remove before production)
  purchaseBanner:   false,  // amber Gumroad banner (only for template showcase)
  cookieBanner:     true,   // GDPR consent banner
  themePicker:      true,   // floating accent colour picker
}

PRICING

Array of plan objects. The monthly/annual toggle is CSS-only.

{
  id:           "pro",
  name:         "Pro",
  badge:        "Most Popular",   // optional pill label
  monthlyPrice: 49,               // number | null ("null" renders "Custom")
  annualPrice:  39,
  annualSavings: 120,
  highlighted:  true,             // accent border + gradient top bar
  cta:          "Start 14-day trial",
  ctaHref:      "/signup?plan=pro",
  features: [
    { text: "Unlimited projects", included: true  },
    { text: "Audit logs",         included: false },
  ],
}

ACCENTS

Presets for the ThemePicker. Add or remove entries freely.

export const ACCENTS = [
  { id: 'indigo', label: 'Indigo', value: '#6366f1' },
  // ...
]

To lock a single brand color and hide the picker, set FEATURE_FLAGS.themePicker: false and update --accent in src/styles/global.css.


HERO

Controls every text and demo value rendered in the homepage hero section. Nothing in Hero.astro or SimulatorWindow.astro is hardcoded.

Copy

export const HERO = {
  badge:         "Early Access",        // shown next to the version pill
  subline: "Ship production-grade SaaS in days — not months.",
  socialProof: {
    label:     "Trusted by engineers at",
    companies: ["Vercel", "Linear", "Stripe", "Railway"],
  },
}

The hero headline is pulled from hero.headline in src/i18n/en/hero.json (and es/hero.json for Spanish), making it fully translatable.

Simulator window

The right-side mock UI window pulls all its data from HERO.simulator:

simulator: {
  windowLabel: "core_dashboard",   // renders as "{SITE.name} — core_dashboard"

  // Metrics tab — three stat cards
  metrics: [
    { label: "Req / min",   value: "24,819", delta: "+12.4%", up: true  },
    { label: "P99 Latency", value: "18 ms",  delta: "−3.2ms", up: true  },
    { label: "Error rate",  value: "0.14%",  delta: "+0.04%", up: false },
  ],

  // Logs tab — array of log entries
  logs: [
    { ts: "09:41:02", level: "INFO",  msg: "Server started on :3000" },
    { ts: "09:41:09", level: "WARN",  msg: "Rate limit approaching: tenant_7f2a (88%)" },
    // level: "INFO" | "DEBUG" | "WARN"
  ],

  // Deploy tab — pipeline steps
  deploySteps: [
    { step: "Git push detected",       status: "done",    sha: "a3f8c12" },
    { step: "Deploy → edge-us-east-1", status: "active",  sha: ""        },
    { step: "Smoke tests",             status: "pending", sha: ""        },
    // status: "done" | "active" | "pending"
    // sha: optional commit hash shown as a badge
  ],

  // Team tab — member cards
  team: [
    { name: "Ana Reyes",  role: "Admin", status: "online",  avatar: "AR" },
    { name: "Ji-woo Park", role: "Dev",  status: "away",    avatar: "JP" },
    // status: "online" | "away" | "offline"
    // avatar: two-letter initials
  ],
}

Common customisations:

Goal What to change
Rename the simulator window simulator.windowLabel
Show your own product metrics simulator.metrics[*].value
Match your tech stack in logs simulator.logs[*].msg
Show your actual team simulator.team
Translate the headline src/i18n/en/hero.jsonhero.headline (also es/hero.json)