Saasdesk Documentation
Introduction
Everything you need to know before you open your editor — what’s in the box, what it’s built with, and what it expects from your machine.
Welcome
Thanks for picking up Saasdesk. This guide walks through installing the template, understanding how the project is organized, customizing content and styling, and shipping it to production. It’s written for developers who are comfortable with the command line but new to this specific codebase — if you already know Astro well, feel free to skip ahead using the sidebar.
What’s Included
Source files
The full, uncompiled project source — components, pages, styles, and configuration.
Build tooling
No pre-built dist/ is bundled — the distributable .zip (built by gulpfile.js) ships source only. Run npm run build yourself to produce dist/.
Design assets
SVG icons and illustrations under public/images/ and src/assets/images/, plus the self-hosted General Sans variable font. No separate Figma file is bundled.
This documentation
A single offline HTML file — open it directly in any browser, no server required.
Features
- A full single-page SaaS/HR marketing site — hero, benefits, features, use cases, testimonial slider, integrations, reviews, pricing, FAQs, client logos, and a “for your team” section
- Matching login and signup pages with shared form styling
- Scroll-driven collapsing navbar animated with GSAP
- Swiper-powered testimonial carousel
- Self-hosted General Sans variable font via Astro’s Fonts API (no external font request)
- Plain CSS design system (
normalize.css,base.css,theme.css) built on CSS custom properties, so re-theming doesn’t require a build-tool config change
Technology Stack
This template is plain Astro — no React or Vue islands, no Tailwind or Sass. Interactivity is handled with small vanilla-JS helpers plus two libraries:
Requirements
| Tool | Minimum version | Notes |
|---|---|---|
| Node.js | 22.12.x or later | Set in package.json’s engines field |
| Package manager | npm 9+, pnpm 8+, or Yarn 1.22+ | Use whichever you prefer; examples below cover all three |
| Code editor | — | VS Code with the Astro extension is a comfortable default |
| Git | 2.x | Only required if you plan to version-control your customized copy |
Browser Support
The built site targets the last two versions of all evergreen browsers:
Internet Explorer 11 is not supported. The template ships no additional polyfills beyond Astro/Vite’s default modern-browser build target.
Getting Started
From a downloaded ZIP to a running dev server in five steps.
Installation & Extraction
- Download the template ZIP from your purchase confirmation email or account downloads page.
- Extract it to a folder on your machine — avoid folder names with spaces or special characters.
- Open that folder in your terminal and in your code editor.
# Extract on macOS / Linux — already nests under sasdesk-astro/
unzip sasdesk-astro.zip
cd sasdesk-astro
Node.js Setup
Check which version of Node.js is currently active:
node --version
# v22.12.x or later
If you manage multiple Node versions, tools like nvm or fnm make switching painless:
nvm install 22
nvm use 22
Install Dependencies
From the project root, install packages with your preferred package manager:
npm install
pnpm install
yarn install
This reads package.json and downloads every dependency into a local node_modules/ folder. It only needs to be re-run when dependencies change.
Run the Development Server
npm run dev
pnpm dev
This starts Astro’s local dev server with hot module reloading — edits to components, pages, and styles appear in the browser immediately without a manual refresh. It’s available at http://localhost:4321 by default; the terminal output will confirm the exact address.
Build for Production & Preview
# Compile an optimized production build into dist/
npm run build
# Serve that build locally to sanity-check it
npm run preview
build type-checks the project, bundles and minifies assets, and writes static output to dist/. preview serves that exact output locally so you can verify it before deploying — it does not rebuild automatically, so re-run build after further changes.
Use dev while you’re customizing the template. Use build, then preview, once before you deploy — it catches issues (like broken TypeScript types or missing imports) that the dev server tolerates but production won’t.
Project Structure
A tour of the folders you’ll actually touch, and the ones you generally shouldn’t.
| Path | Purpose |
|---|---|
public/ | Files here are copied to the output root untouched — no optimization or hashing. Holds favicon.ico/favicon.svg, the plain CSS entry files, the local font, and section icon SVGs. |
src/components/ | One .astro component per page section (Hero, Benefits, Features, Pricing, Navbar, Footer, etc.), plus a shared PrimaryButton. |
src/layouts/ | Layout.astro — the common page shell: <head> tags, font preload, the Navbar, and the scroll-collapse script. |
src/pages/ | Every file here becomes a route automatically. See Pages for details. |
src/assets/ | Images and the local font file that should be optimized/bundled by the build. See Images & Assets. |
src/styles/ | global.css — a small set of shared hover-animation rules that can’t live in a single component’s scoped styles. See Styling. |
src/data/ | Structured content (navigation, pricing tiers, testimonials, FAQs, site-wide settings) kept separate from markup so it’s easy to edit without touching Astro templates. |
gulpfile.js packages the whole project into a distributable .zip via npm run zip — you generally won’t need to touch it unless you’re changing what ships in that archive.
Configuration
The files that control how the project builds, and where to set site-wide values.
package.json
Defines dependencies and the scripts you run from the terminal (dev, build, preview). Add your own script here if you introduce a new tool.
{
"name": "sasdesk-astro",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"zip": "gulp"
}
}
astro.config.mjs
Controls integrations, the deployed site URL, and build behavior. This template only uses it to register the self-hosted local font:
import { defineConfig, fontProviders } from 'astro/config';
export default defineConfig({
fonts: [
{
provider: fontProviders.local(),
name: 'Generalsans Variable',
cssVariable: '--font-sans',
options: {
variants: [{ weight: '200 700', style: 'normal', src: ['./src/assets/fonts/GeneralSans-Variable.ttf'] }],
},
},
],
});
There’s no site value set yet — add one before deploying (see SEO and Deployment, both of which rely on it for absolute URLs).
tsconfig.json
Extends Astro’s strict preset for type-checking .astro files and astro.config.mjs. No path aliases are configured — every import uses a relative path (e.g. ../components/Hero.astro):
{
"extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
Environment Variables (.env)
This template doesn’t define or read any environment variables out of the box — everything (copy, links, pricing) lives in src/data/ instead. If you add an integration that needs one (an API key, a form endpoint), create a .env file in the project root; variables must be prefixed PUBLIC_ to be readable in client-side code:
# Exposed to the browser — never put secrets here
PUBLIC_SITE_URL=https://example.com
# Server-only — safe for secrets, not readable in browser code
API_SECRET_KEY=your_secret_key
Add .env to .gitignore before creating one. Anything without the PUBLIC_ prefix should stay off the client entirely.
Pages
How routes are created, and how this template’s pages are put together.
Creating a New Page
Astro uses file-based routing: any .astro or .md file placed in src/pages/ automatically becomes a route matching its file path. This template currently ships three, all flat — no nested folders or dynamic segments:
src/pages/index.astro → /
src/pages/login.astro → /login
src/pages/signup.astro → /signup
To add a page, create a new file in src/pages/ using login.astro or signup.astro as a starting point — both follow the same pattern of importing Layout and Footer directly:
---
import Layout from '../layouts/Layout.astro';
import Footer from '../components/Footer.astro';
---
<Layout title="Pricing | Saasdesk" description="...">
<h1>Pricing Plans</h1>
<Footer />
</Layout>
Editing an Existing Page
Open the relevant file under src/pages/ and edit the markup directly. index.astro itself contains no copy — it’s just an ordered list of section components (Hero, Benefits, Features, UseCases, Testimonial, Integrations, Reviews, Pricing, FAQs, ClientLogos, ForTeam, Footer) — reorder or remove sections there, and edit each section’s actual text inside its component in src/components/ or its data file in src/data/.
Dynamic Routes
This template doesn’t currently use any — all three routes above are static files. If you add something that needs one template per item (a blog post, a plan detail page), a file wrapped in square brackets, such as [slug].astro, generates multiple pages from a single template. Astro requires a getStaticPaths() function for these on statically-generated sites:
---
export async function getStaticPaths() {
const posts = await import.meta.glob('./posts/*.md');
return Object.keys(posts).map((path) => ({
params: { slug: path.split('/').pop().replace('.md', '') },
}));
}
---
Layouts
src/layouts/Layout.astro is the only layout, and every page renders through it via a <slot />. It sets up the <head> (title, description, Open Graph/Twitter tags, favicon), preloads the local font, renders <Navbar />, and includes the scroll script that collapses the header into a sticky navbar:
---
import { Font } from 'astro:assets';
import Navbar from '../components/Navbar.astro';
import '../styles/global.css';
const { title, description } = Astro.props;
---
<html lang="en">
<head><title>{title}</title></head>
<body>
<Navbar />
<slot /> <!-- page content is injected here -->
</body>
</html>
title is required; description is optional and, when passed, also fills the meta description and Open Graph/Twitter tags. Neither is declared with a TypeScript interface — they’re read straight off Astro.props.
Page Metadata & the 404 Page
Pass a title and description into Layout on every page for correct browser tabs and search results (see also SEO). There’s no 404.astro in this template yet — add one to src/pages/ and Astro will serve it automatically whenever no route matches.
Components
The building blocks pages are assembled from, and how data flows into them.
Reusable Components
Components live in src/components/ and encapsulate one piece of UI. Most are one-per-page-section (Hero.astro, Benefits.astro, Pricing.astro, ...), pulling their copy from a matching file in src/data/; PrimaryButton.astro is the one genuinely shared, reused-across-sections component. Every component here is plain .astro — there are no .tsx/React components or client-side islands in this template.
Props
Props are the inputs a component accepts, similar to HTML attributes. This template reads them straight off Astro.props without declaring a TypeScript interface for them — PrimaryButton.astro is a representative example:
---
const { href, text } = Astro.props;
---
<a href={href} class="primary-button w-inline-block">
<div class="button-text">{text}</div>
</a>
If you want compile-time checking for a component’s props, add an interface Props { ... } above the frontmatter destructure — the strict tsconfig.json (see Configuration) will then type-check it.
Component Composition
index.astro is itself a composition of section components with no markup of its own — each section (Hero, Benefits, Features, UseCases, Testimonial, Integrations, Reviews, Pricing, FAQs, ClientLogos, ForTeam, Footer) is dropped in as its own tag and reads its own content from src/data/. Reorder the page by reordering these tags.
Passing Data to Components
Component tags accept props the same way as HTML attributes, read via Astro.props. Most section components in this template don’t take props at all — they import their own content directly from a matching src/data/*.js file. PrimaryButton is one that does:
<PrimaryButton href="/signup" text="Get Started" />
Styling
Where to change colors, type, and spacing without fighting the build.
Global Styles & CSS Variables
This template’s design tokens live in public/css/theme.css, not src/styles/ — it’s loaded as a plain <link> in Layout.astro alongside normalize.css and base.css, rather than imported into the Astro build. Colors are CSS custom properties on :root:
:root {
--color--grey: #6a6a7a;
--color--accent: #00acca;
--color--dark: #2b2b46;
--color--blue: #e6fbff;
--color--green: #e6fff0;
--color--purple: #e6e8ff;
}
src/styles/global.css is much smaller by comparison — it only holds the shared hover-animation rules for .secondary-button variants that appear in multiple components and so can’t live in any one component’s scoped <style> block.
Component Styles
Astro components support scoped <style> blocks — CSS written there only applies to that component, so class names never collide across files. Most components in this template (e.g. PrimaryButton.astro) keep their own hover/interaction styles this way:
<style>
.primary-button:hover .button-arrow-bg { transform: scale(3.75); }
</style>
Responsive Design, Typography & Spacing
Breakpoints, spacing, and the type scale are defined in public/css/theme.css and base.css rather than global.css. Prefer adjusting these shared values over overriding sizes on individual elements, so the site keeps a consistent rhythm as you edit it. Fonts use the CSS variable set up by Astro’s Fonts API — see Fonts & Icons.
The dist/ folder is generated output — any change made there is overwritten on the next build. Always edit files under src/ or public/.
Images & Assets
Two homes for static files, and when to use each.
| Location | Use for | Behavior |
|---|---|---|
src/assets/ | Images referenced inside components or pages | Content-hashed by the build; resized/re-encoded too, but only for images rendered through the Image component (not the plain <img src={x.src}> pattern used for some icons — see below) |
public/ | Files that need a fixed, predictable URL (favicons, downloadable PDFs, og-image.jpg) | Copied as-is, no processing |
Replacing Images
Components like Hero.astro import a photo from src/assets/images/ and render it through the optimized Image component — swap the file in place (keeping the same filename) or update the import to point at your new file:
---
import { Image } from 'astro:assets';
import heroImage from '../assets/images/hero-image.webp';
---
<Image src={heroImage} alt="..." />
Icons and simpler UI images (like the checkmark on the login/signup pages) instead import the file as a plain module and read its resolved URL off .src, rendering a bare <img> rather than the Image component:
---
import checkmarkIcon from '../assets/images/checkmark.svg';
---
<img src={checkmarkIcon.src} loading="lazy" alt="check mark" />
Most other icons live directly in public/images/ and are referenced by a plain root-relative path (e.g. /images/benefit-icon-1.svg) with no import at all.
Supported Formats & SVGs
JPEG, PNG, WebP, AVIF, and GIF are supported through the optimized Image component (this template’s hero and section photos are .webp). SVG icons are imported as plain modules (see above) or referenced directly from public/images/ as static files.
Image Optimization
Images imported from src/assets/ are automatically resized and re-encoded at build time based on the width/height (or densities/widths) you specify — you generally don’t need a separate compression step before adding an image to the project.
If an image is part of the design (hero photos, thumbnails, icons), put it in src/assets/. If a URL needs to work regardless of the build (a favicon, a file linked from an email), put it in public/.
Fonts & Icons
Swapping typefaces and icon sets without touching every component.
Local Fonts
This template loads no Google (or other remote) fonts — its one typeface, General Sans, is self-hosted and registered through Astro’s built-in Fonts API instead of a manual @font-face block:
fonts: [
{
provider: fontProviders.local(),
name: 'Generalsans Variable',
cssVariable: '--font-sans',
options: { variants: [{ weight: '200 700', style: 'normal', src: ['./src/assets/fonts/GeneralSans-Variable.ttf'] }] },
},
]
The variable font file lives at src/assets/fonts/GeneralSans-Variable.ttf and is preloaded in Layout.astro with <Font cssVariable="--font-sans" preload />; use the resulting var(--font-sans) anywhere in CSS. To swap the typeface, replace the font file and update name/src here — no @font-face rule to touch.
Icon Libraries
No icon library is used. Every icon is a standalone SVG file under public/images/ (referenced by root-relative path) or src/assets/images/ (imported and rendered via <img src={icon.src}> or the Image component — see Images & Assets).
Replacing & Adding Icons
Swap the SVG file in place (keeping the filename) to replace an icon, or add a new SVG to public/images/ (for a root-relative reference) or src/assets/images/ (to import it) and reference it the same way as its neighbors.
Content Editing
The fastest, lowest-risk way to make the site say what you want it to say.
Everything in this section is plain text or attribute changes — no logic to break. Save the file, and your dev server (from Getting Started) will refresh the browser automatically so you can see the change right away.
Headings, Paragraphs & Buttons
Find the relevant component in src/components/, locate the text between the tags, and edit it directly — e.g. the hero heading and CTA in Hero.astro:
<!-- before -->
<h1>All-in-one Payroll and HR System for small team</h1>
<PrimaryButton href="/signup" text="Get Started" />
<!-- after -->
<h1>Everything Your HR Team Needs</h1>
<PrimaryButton href="/signup" text="Start Free Trial" />
Navigation & Footer
Header links are hardcoded directly in Navbar.astro’s markup; footer links are data-driven from src/data/footer.js. See Navigation for the full pattern and why the two differ.
Cards, Testimonials & Pricing
Repeating content blocks (reviews, pricing tiers, FAQs, benefits) are driven by a data array in src/data/ rather than hand-written per card, so adding or removing an item is a matter of editing the list:
export const reviews = [
{
image: clientImage3,
stat: '3x',
statLabel: 'Faster Hiring',
quote: 'They have a great understanding of HR strategies...',
name: 'Adam Smith',
title: 'Co-Founder & CEO',
},
// ...
];
The matching .astro component (e.g. Reviews.astro, Pricing.astro, FAQs.astro) imports this array and loops over it — you rarely need to touch the component itself just to change copy.
Contact Information
There’s no blog in this template. Contact details (email, phone) and social/app-store links live in one place, src/data/site-config.js, and are imported wherever they’re shown (e.g. the footer):
export const siteConfig = {
name: 'Saasdesk',
contact: { email: 'hello@example.com', phone: '123-456-7890' },
social: { facebook: '...', instagram: '...', linkedin: '...' },
};
Forms
What ships out of the box, and what still needs a backend.
This template has no newsletter or contact form — only the login and signup forms below. Neither is wired to a backend, an action URL, or a submit handler; submitting either does nothing yet. Connect them to your own auth backend or a third-party service before shipping.
Login & Signup Forms
src/pages/login.astro and signup.astro each render a plain HTML <form> with named inputs and no JavaScript submit handler:
<form name="wf-form-Login-Form" class="utility-form">
<input class="input-field w-input" name="Work-Email" type="email" required />
<input class="input-field w-input" name="Password" type="password" required />
<input type="submit" class="submit-button w-button" value="Login" />
</form>
To make these functional, add an action pointing at your auth endpoint, or attach a submit handler in an inline <script> (see Navigation for how this template already does that pattern elsewhere) that calls your own API or a third-party auth provider.
Form Validation
Both forms rely entirely on native HTML attributes (required, type="email", maxlength) for validation — there’s no custom JavaScript validation function to extend or replace.
Third-Party Form Services
Since neither form currently submits anywhere, services like Formspree, Getform, or Basin (which accept submissions directly from static HTML) are a fast way to make them functional — typically just adding an action attribute pointing at the service.
API & Data
Not applicable to this template — noted here for completeness.
This template makes no fetch calls and reads no environment variables. Every piece of content (pricing, reviews, FAQs, benefits, navigation) is a static array in src/data/*.js, imported directly by the component that renders it — see Content Editing. If you later wire this up to a real API or CMS, that's the place each affected component would switch from a static import to a fetch call.
SEO
Per-page metadata, social previews, and the machine-readable files search engines expect.
Page Title & Meta Description
Pass a unique title and description into Layout on every page — these drive both the browser tab and the snippet shown in search results, and Layout.astro automatically mirrors them into Open Graph and Twitter tags too:
<Layout
title="Saasdesk - All-in-one Payroll and HR System for small teams"
description="Helping them establish efficient HR operations, manage growing teams, and stay compliant."
>
Open Graph & Twitter/X Cards
Layout.astro already sets og:type, og:title, og:description, twitter:card, twitter:title, and twitter:description from the same title/description props. Two things it does not set yet: a canonical <link> and an og:image — add both once you have a real domain and a social preview image:
<link rel="canonical" href={Astro.url.href} />
<meta property="og:image" content="[absolute URL to a social preview image]" />
Sitemap & Robots.txt
Neither exists yet in this template — there’s no public/robots.txt and Astro’s official sitemap integration (@astrojs/sitemap) isn’t installed. To add a sitemap, run astro add sitemap and set a site value in astro.config.mjs (see Configuration); to add crawler rules, create public/robots.txt:
User-agent: *
Allow: /
Sitemap: https://example.com/sitemap-index.xml
Structured Data & Semantic HTML
Use landmark elements (<header>, <nav>, <main>, <article>) and a single <h1> per page so both search engines and screen readers can parse the page’s structure. Add JSON-LD structured data in the layout’s <head> for rich results (e.g. Organization or Article schema) where relevant to your content.
Deployment
Platform-by-platform steps. Confirm your rendering mode first — it changes the build output you deploy.
No SSR adapter is configured, so npm run build produces plain HTML/CSS/JS in dist/ that any static host can serve as-is — no Node process required at runtime.
Vercel
- Push the project to a GitHub, GitLab, or Bitbucket repository.
- In Vercel, choose Add New → Project and import that repository.
- Build command:
npm run build· Output directory:dist(Astro static) — Vercel’s Astro preset detects this automatically in most cases. - Add any environment variables from your
.envfile under Project Settings → Environment Variables. - Click Deploy.
Netlify
[build]
command = "npm run build"
publish = "dist"
Connect the repository in the Netlify dashboard, confirm these build settings, add environment variables under Site configuration → Environment variables, and deploy.
Cloudflare Pages
Connect the repository, set the build command to npm run build and the output directory to dist. For SSR Astro sites, use the official @astrojs/cloudflare adapter instead of the static preset.
GitHub Pages
Set site and base in astro.config.mjs to match your repository URL, then build and publish the dist/ folder to the gh-pages branch (via the official astro build + a deploy action, or manually). GitHub Pages only serves static output — it cannot run an SSR adapter.
Traditional Hosting
For a static build, upload the contents of dist/ to your host’s public web root via FTP/SFTP or your host’s file manager. For an SSR build or a React/Vite app that needs a Node process, the host must support running node continuously (a VPS or a Node-compatible host) — plain shared hosting without Node support cannot run it.
Build & Production
What happens when you run build, and a checklist before you ship.
npm run build # type-check, bundle, and write dist/
npm run preview # serve dist/ locally, exactly as it will run in production
Build Output
The build writes static HTML, hashed CSS/JS bundles, and optimized images to dist/ (or build/, for some Vite/React setups). This folder is disposable and regenerated by every build — it’s conventional to keep it out of Git via .gitignore.
Environment Variables in Production
Variables from your local .env are not deployed automatically — each hosting platform requires you to set them again in its dashboard (see Deployment). A missing production variable is one of the most common causes of a build that works locally but fails, or behaves unexpectedly, once deployed.
Production Checklist
- Run
npm run buildlocally and confirm it completes with no errors. - Run
npm run previewand click through the main pages. - Confirm the
siteURL inastro.config.mjsmatches your real domain. - Set every environment variable from
.envin your hosting platform’s dashboard. - Check that forms, if any, point at a real endpoint rather than a placeholder.
- Verify favicon, Open Graph image, and meta descriptions are your own, not the template defaults.
Troubleshooting
The most common problems, in the order you’re likely to hit them.
npm install fails
- Cause
- Node.js version too old, a corrupted local cache, or a stale lockfile from a different package manager.
- Solution
- Confirm
node --versionmeets the requirement in Requirements, then runrm -rf node_modules package-lock.json && npm install.
Port already in use
- Cause
- Another process (often a previous dev server that didn’t shut down cleanly) is already listening on the default port.
- Solution
- Stop the other process, or start this one on a different port:
npm run dev -- --port 4322.
Module not found
- Cause
- A missing dependency, or a typo in a relative import path — this template uses no
tsconfig.jsonpath aliases, so every import is a real relative path.
- Solution
- Re-run
npm install; check the import path and casing matches the file’s actual location exactly.
Images not loading
- Cause
- An incorrect relative path, or an image placed in
src/assets/but referenced with apublic/-style absolute path (or vice versa).
- Solution
- Review Images & Assets — imported assets need an
importstatement;public/files need a root-relative URL like/logo.svg.
Styles not loading
- Cause
- One of the plain
<link>tags inLayout.astro(normalize.css,base.css,theme.css) is missing, or a component’s scoped<style>block has a typo in a class name it targets.
- Solution
- Confirm all three stylesheet
<link>tags are present inLayout.astro’s<head>; check the class name in the component markup matches the one in its<style>block exactly.
TypeScript errors
- Cause
- Most errors here come from the strict
tsconfig.jsontype-checking an.astrofile itself (e.g. an unhandlednull), rather than a props mismatch — components in this template don’t declare a typedinterfacefor their props (see Props).
- Solution
- Read the error’s file and line number; if you’ve added your own
interface Propsto a component, compare it against how that component is actually called.
Build fails (but dev server works)
- Cause
- The dev server is more forgiving than
build, which fully type-checks the project — an issue tolerated in dev can fail the build.
- Solution
- Read the full terminal output for the first error (later errors are often side effects of it); fix issues top to bottom and re-run.
Environment variables not working
- Cause
- Missing the
PUBLIC_prefix for a client-side value, or the dev server wasn’t restarted after editing.env.
- Solution
- Rename the variable with the
PUBLIC_prefix if it’s used in browser code, then stop and restartnpm run dev— env changes aren’t hot-reloaded.
Deployment problems
- Cause
- Wrong output directory configured on the host, or environment variables set locally but not in the platform’s dashboard.
- Solution
- Re-check the build command and output folder against Deployment for your platform, and confirm every variable from
.envis duplicated there.
FAQ
Quick answers to the questions we hear most.
How do I install the template?
Extract the ZIP, run your package manager’s install command, then start the dev server. The full walkthrough is in Getting Started.
Which Node.js version should I use?
Node 22.12 or later — this is enforced by the engines field in package.json, not just a recommendation. See Requirements.
Does this template use TypeScript?
Only for type-checking — tsconfig.json extends Astro’s strict preset, but every data file is plain .js and no component declares a typed Props interface. See Configuration.
How do I change colors?
Update the CSS custom properties in public/css/theme.css — see Styling.
How do I change fonts?
Swap the font import and update the corresponding --font-* variable — see Fonts & Icons.
How do I replace images?
Swap the file or update the import path — see Images & Assets.
How do I add a new page?
Add a file to src/pages/; the route is created automatically — see Pages.
How do I deploy the template?
Platform-specific steps for Vercel, Netlify, Cloudflare Pages, GitHub Pages, and traditional hosts are in Deployment.
Can I use the template commercially?
[State your license terms here — e.g. standard vs. extended license — and link to the full license text.]
Where can I get support?
See the Support section for contact details and what to include in a request.
Changelog
Every notable change, newest first. Add a new entry above the last one for each release.
- AddedInitial release.
Copy the markup for one entry above, update the version number, date, and bullet list, and place it at the top of this section for each new release.
Support
Stuck on something this guide didn’t cover? Here’s how to reach us.
Documentation
Most questions are answered somewhere in this guide — try the search (Ctrl K) before reaching out.
Back to topSupport hours
We’re based in India and available Monday–Friday, 10am–7pm IST. Expect a response within 24 hours.
What to Include in a Support Request
The fastest way to get a useful answer is to include the details below in your first message:
When contacting support, please include:
- Template name and version
- Browser (and version)
- Operating system
- Node.js version (node --version)
- The exact error message
- Steps to reproduce the problem