Techwave Documentation

01 · Overview

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 Techwave, a multi-page Astro theme for IT service companies, help desks, and SaaS support teams. 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.

Production build

No pre-built dist/ folder is shipped — run npm run build once to generate one (see Build & Preview).

Design assets

Self-hosted Satoshi font files in public/fonts/, light and dark SVG logos, and the demo PNG/JPG artwork in public/images/. No Figma file is included.

This documentation

Hosted online — the link is in the documentation.txt file included alongside the template folder in the download.

Features

  • Home, Features, Solutions, Why Choose Us, Pricing, About, Careers, and Contact pages, plus Book a Demo, Sign In, Sign Up, Privacy Policy, Terms of Use, and a 404 page
  • A full blog: a default blog page with a featured slider and sidebar, 11 more listing styles (Grid 1–5, Masonry, Gallery 1–3, Lateral, Listing), and author, category, tag, and post-format archives
  • Five post formats (standard, gallery, audio, video, quote) with hero or classic headers, comments, related posts, and previous/next links — all written in Markdown content collections
  • Mega menu, mobile drawer menu, search overlay, and a back-to-top button
  • GSAP + ScrollTrigger scroll animations that respect prefers-reduced-motion, and Swiper sliders
  • Monthly/yearly pricing table, tabs, accordions, count-up stats, and a lightbox
  • Page copy, navigation, footer, pricing, testimonials, and form fields kept in plain JavaScript data files under src/data/
  • Canonical URLs, Open Graph and Twitter card tags on every page, and an automatic sitemap

Technology Stack

Techwave is built with .astro components, plain CSS, and vanilla JavaScript — no UI framework, no CSS framework, and no TypeScript source files.

Astro 7 Vite GSAP Swiper Fontsource @astrojs/sitemap

Requirements

ToolMinimum versionNotes
Node.js22.12.0 or laterRequired by Astro 7 (set in package.json → engines)
Package managernpm 9+, pnpm 8+, or Yarn 1.22+A package-lock.json is included, so npm reproduces the tested dependency versions exactly
Code editor—VS Code with the official Astro extension is a comfortable default
Git2.xOnly required if you plan to version-control your customized copy

Browser Support

The built site targets the last two versions of all evergreen browsers:

Chrome Firefox Safari Edge
Internet Explorer

Internet Explorer 11 is not supported. The template ships no polyfills.

02 · Setup

Getting Started

From a downloaded ZIP to a running dev server in five steps.

Installation & Extraction

  1. Download the template ZIP from your purchase confirmation email or account downloads page.
  2. Extract it to a folder on your machine — avoid folder names with spaces or special characters.
  3. Open that folder in your terminal and in your code editor.
bash
# Extract on macOS / Linux
unzip techwave-astro-package.zip
cd techwave-astro-package/techwave-astro

Node.js Setup

Check which version of Node.js is currently active:

bash
node --version
# v22.12.0 or later

If you manage multiple Node versions, tools like nvm or fnm make switching painless:

bash
nvm install 22
nvm use 22

Install Dependencies

From the project root, install packages with your preferred package manager:

npm
npm install
pnpm
pnpm install
yarn
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
npm run dev
pnpm
pnpm dev

This starts Vite’s local dev server with hot module reloading — edits to components, pages, and styles appear in the browser immediately without a manual refresh. By default it’s available at http://localhost:4321; the terminal output will confirm the exact address.

Build for Production & Preview

bash
# Compile an optimized production build into dist/
npm run build

# Serve that build locally to sanity-check it
npm run preview

build validates content collections, 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.

Which command do I actually need?

Use dev while you’re customizing the template. Use build, then preview, once before you deploy — it catches issues (like invalid blog front matter or missing imports) that the dev server tolerates but production won’t.

03 · Reference

Project Structure

A tour of the folders you’ll actually touch, and the ones you generally shouldn’t.

PathPurpose
public/Files here are copied to the output root untouched — no optimization or hashing. This template keeps every image here (public/images/), plus the Satoshi font files and the favicons.
src/components/Site-wide pieces (Header, Footer, MegaMenu, MobileMenu, SearchOverlay, BackToTop, Icon, Badge), page sections in sections/<page>/ (sections reused on several pages are in sections/shared/), and small building blocks in ui/.
src/content/Markdown content collections: blog/ (one file per post) and legal/ (privacy policy and terms of use). Their front-matter schemas are in src/content.config.js.
src/layouts/Layout.astro is the page shell for every page — <head> tags, fonts, header, footer. PostLayout.astro renders a single blog post and ArchiveLayout.astro renders author/category/tag/format archives.
src/pages/Every file here becomes a route automatically. See Pages for details.
src/scripts/Client-side scripts shared by several sections: reveal.js (GSAP scroll animations), accordion.js, count-up.js, and lightbox.js.
src/styles/global.css — the Satoshi @font-face rules, color and font variables, and base typography. See Styling.
src/data/Plain JavaScript files holding page copy, navigation, footer, pricing, testimonials, blog listing settings, authors, and form fields — kept separate from markup so you can edit text without touching .astro files.
src/utils/blog.js — helpers for post/category/tag/author URLs, date formatting, related posts, and the pagination paths used by the blog routes.
Files not shown above

package-lock.json (exact dependency versions for npm) and .gitignore. Generated folders — node_modules/, .astro/, and dist/ — are created by npm install, the dev server, and npm run build; never edit them by hand.

04 · Reference

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.

jsonpackage.json
{
  "name": "techwave-astro",
  "type": "module",
  "version": "0.0.1",
  "engines": { "node": ">=22.12.0" },
  "scripts": {
    "dev": "astro dev",
    "build": "astro build",
    "preview": "astro preview",
    "astro": "astro"
  },
  "dependencies": {
    "@astrojs/sitemap": "^3.7.4",
    "@fontsource/inter": "^5.3.0",
    "@fontsource/manrope": "^5.3.0",
    "@fontsource/outfit": "^5.3.0",
    "astro": "^7.3.5",
    "gsap": "^3.15.0",
    "sharp": "^0.35.5",
    "swiper": "^14.3.0"
  }
}

astro.config.mjs

Controls integrations, the deployed site URL, and build behavior. Techwave registers only the sitemap integration (the 404 page is left out of the sitemap) and turns off Astro’s dev toolbar. Replace the site value with your real domain before deploying — it is used for canonical URLs, Open Graph image URLs, and the sitemap.

javascriptastro.config.mjs
// @ts-check
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

// https://astro.build/config
export default defineConfig({
  // Replace with the production domain; used for canonical URLs, OG images and the sitemap.
  site: 'https://techwave.example.com',
  integrations: [sitemap({ filter: (page) => !page.endsWith('/404/') })],
  devToolbar: { enabled: false },
});

tsconfig.json

The project’s source is plain JavaScript and .astro files; tsconfig.json only extends Astro’s strict preset so your editor understands Astro’s generated types. No path aliases are defined — imports use relative paths such as ../components/Header.astro.

jsontsconfig.json
{
  "extends": "astro/tsconfigs/strict",
  "include": [".astro/types.d.ts", "**/*"],
  "exclude": ["dist"]
}

Environment Variables (.env)

Techwave doesn’t read any environment variables out of the box, so no .env file is needed. If you add one later (for example for a form service key), create it in the project root. Variables must be prefixed PUBLIC_ to be readable in client-side code.

env.env
# 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
Never commit .env

Add .env to .gitignore (it usually is by default). Anything without the PUBLIC_ prefix should stay off the client entirely.

05 · Guide

Pages

How routes are created, which pages ship with the template, and how the blog routes are generated.

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. Techwave ships these routes:

text
src/pages/index.astro                    →  /
src/pages/features.astro                 →  /features
src/pages/solutions.astro                →  /solutions
src/pages/why-choose-us.astro            →  /why-choose-us
src/pages/pricing.astro                  →  /pricing
src/pages/about.astro                    →  /about
src/pages/careers.astro                  →  /careers
src/pages/contact.astro                  →  /contact
src/pages/demo.astro                     →  /demo
src/pages/sign-in.astro                  →  /sign-in
src/pages/sign-up.astro                  →  /sign-up
src/pages/404.astro                      →  not-found page
src/pages/[legal].astro                  →  /privacy-policy, /terms-of-use
src/pages/[post].astro                   →  /<post-slug>  (one per blog post)
src/pages/blog/[...page].astro           →  /blog, /blog/page/2, …
src/pages/[listing]/[...page].astro      →  /grid … /grid-5, /masonry, /gallery … /gallery-3, /lateral, /listing
src/pages/author/[slug]/[...page].astro  →  /author/<slug>
src/pages/category/[slug]/[...page].astro →  /category/<slug>
src/pages/tag/[slug]/[...page].astro     →  /tag/<slug>
src/pages/type/[slug]/[...page].astro    →  /type/<format>  (post-format archive)

To add a page, create a new file in src/pages/ using the layout and structure of an existing, similar page as a starting point. Sections in src/components/sections/shared/ are designed to be dropped onto any page:

astrosrc/pages/services.astro
---
import Layout from '../layouts/Layout.astro';
import SectionIntro from '../components/sections/shared/SectionIntro.astro';
import CtaBand from '../components/sections/shared/CtaBand.astro';
import { cta } from '../data/home.js';
---
<Layout title="Services – Techwave" description="Managed IT services for growing teams.">
  <SectionIntro heading="Our Services" text="Everything your team needs, in one place." />
  <CtaBand {...cta} />
</Layout>

Editing an Existing Page

Page files in src/pages/ are short: they import section components and pass them data from the matching file in src/data/ (for example index.astro reads src/data/home.js, about.astro reads src/data/about.js). To change wording or images, edit the data file; to change layout or markup, edit the section component under src/components/sections/. Sections in sections/shared/ (pricing table, testimonials, CTA band, …) appear on several pages, so a markup change there affects all of them.

Dynamic Routes

Files wrapped in square brackets, such as [post].astro, generate multiple pages from a single template — here, one page per blog post, legal page, listing style, and archive. Astro requires a getStaticPaths() function for these on statically-generated sites. The single-post route reads the blog collection through a helper in src/utils/blog.js:

astrosrc/pages/[post].astro
---
// Blog posts at /<slug>, one per Markdown entry in src/content/blog.
import PostLayout from '../layouts/PostLayout.astro';
import { getPosts } from '../utils/blog.js';

export async function getStaticPaths() {
  const posts = await getPosts();
  return posts.map((post) => ({ params: { post: post.id }, props: { post, posts } }));
}

const { post, posts } = Astro.props;
---

<PostLayout post={post} posts={posts} />

The blog listing styles (titles, posts per page, card layout) are configured in src/data/listings.js; adding an entry there adds a new listing route automatically.

Layouts

Layouts (in src/layouts/) wrap page content with shared structure — the <html> shell, <head> metadata, header, and footer. Every page renders inside Layout.astro via a <slot />; PostLayout and ArchiveLayout build on it for blog posts and archives. Simplified:

astrosrc/layouts/Layout.astro
---
import '../styles/global.css';
const {
  title = 'Techwave – IT Solutions & Help Desk',
  description = 'Techwave helps businesses grow with managed IT, …',
  image = '/images/logo-dark.svg',
  header = {}, // Header variant props: { topbar, scheme, position, size }
  footer = true, // false on pages with their own minimal footer
} = Astro.props;
---
<html lang="en">
  <head><title>{title}</title> … </head>
  <body id="top">
    <BackToTop />
    <Header {...header} />
    <main id="main"><slot /></main> <!-- page content is injected here -->
    {footer && <Footer />}
  </body>
</html>

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); pages that omit them fall back to the defaults above. src/pages/404.astro is served automatically whenever no route matches.

06 · Guide

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 — a button, a post card, a navigation bar — so it can be reused across pages without copy-pasting markup. Every component in Techwave is an .astro file, organized in three groups:

FolderContents
src/components/Header, MegaMenu, MobileMenu, SearchOverlay, Footer, BackToTop, Icon (inline SVG icons), Badge
src/components/ui/PillButton, ArrowLink, PlayButton, LeadForm, LogoMarquee, PostCard, PostListItem, Pagination, BlogSidebar
src/components/sections/Page sections in one folder per page (home/, features/, about/, careers/, contact/, pricing/, solutions/, why-choose-us/, blog/, post/, archive/), plus shared/ for sections used on several pages (PricingTable, Testimonials, CtaBand, FeatureRow, SectionIntro, PostGrid, …)

Props

Props are the inputs a component accepts, similar to HTML attributes. Techwave components are written in plain JavaScript, so props are read by destructuring Astro.props, with defaults set right there and a comment at the top of the file describing the options. For example, the pill-shaped button used across the site:

astrosrc/components/ui/PillButton.astro
---
// Large pill button; on hover the label slides up and a copy slides in from below.
const { href, label, tone = 'accent', size = 'lg', class: className, ...rest } = Astro.props;
---

<a href={href} class:list={['pill-btn', `pill-btn--${tone}`, `pill-btn--${size}`, className]} {...rest}>
  <span data-text={label}>{label}</span>
</a>

In plain language: href and label set the link and its text; tone and size are optional and pick a color/size modifier class (defaulting to accent and lg); any extra attributes (such as target) are passed straight through to the <a>.

Component Composition

Larger sections are composed from smaller components rather than written as one long block of markup. The home page, for example, is just a list of sections:

astrosrc/pages/index.astro
<Layout>
  <Hero {...hero} />
  <LogoSlider logos={homeLogos} />
  <SectionIntro {...intro} />
  <FeatureTabs tabs={featureTabs} />
  <FeatureRow {...liveChat} />
  <PaymentMethods {...payments} />
  <IconCards {...iconCards} />
  <RevenueStats {...revenue} />
  <BenefitsSlider {...benefits} />
  <PricingTable />
  <Testimonials />
  <CtaBand {...cta} />
</Layout>

Passing Data to Components

In Astro, props are passed the same way as HTML attributes and read via Astro.props. Most pages import an object from src/data/ and spread it into the section:

astro
---
import PillButton from '../components/ui/PillButton.astro';
import CtaBand from '../components/sections/shared/CtaBand.astro';
import { cta } from '../data/home.js';
---
<PillButton href="/" label="Back to home" />
<CtaBand {...cta} tone="coral" />
Interactivity without a UI framework

Interactive pieces — the mega menu, mobile drawer, search overlay, tabs, accordions, sliders, and scroll animations — use small vanilla JavaScript <script> blocks inside their .astro component (or shared scripts in src/scripts/). Astro bundles and loads these automatically; no client: directives are needed.

07 · Guide

Styling

Where to change colors, type, and spacing without fighting the build.

Global Styles & CSS Variables

Techwave is styled with plain CSS — no Tailwind or Sass. Site-wide values (color palette and font families) are defined once as CSS custom properties in src/styles/global.css, which Layout.astro imports on every page. Change a value here and it updates across the whole site:

csssrc/styles/global.css
:root {
  --color-primary: #171c47;    /* navy: headings */
  --color-secondary: #5d607e;
  --color-text: #63667f;
  --color-body: #57597a;       /* body copy */
  --color-accent: #e1534a;     /* coral: accent buttons, eyebrow labels */
  --color-white: #ffffff;
  --color-blush: #fceeed;
  --color-lavender: #f0e8fd;
  --color-mint: #e6f7f1;
  --color-sky: #e6eeff;
  --color-periwinkle: #e9ebf9;

  --font-heading: 'Manrope', sans-serif;
  --font-body: 'Satoshi', sans-serif;
  --font-button: 'Inter', sans-serif;
}

Component Styles

Astro components support scoped <style> blocks — CSS written there only applies to that component, so class names never collide across files. Almost all of Techwave’s layout CSS lives this way, at the bottom of each component file, and reads the shared variables:

astrosrc/components/ui/PillButton.astro
<style>
  .pill-btn {
    padding: 17.5px 44px;
    border-radius: 50px;
    font-family: var(--font-heading);
    font-weight: 700;
  }
</style>

Responsive Design, Typography & Spacing

The heading scale (h1–h6, all Manrope 700) and the body text size are set in global.css, with smaller h1/h2 sizes below 767px. Each component’s scoped styles then adjust its own layout at the template’s breakpoints — 1366px, 1200px, 1024px, 880px, and 767px (max-width media queries). Prefer adjusting the shared values in global.css over overriding sizes on individual elements, so the site keeps a consistent rhythm as you edit it.

Avoid editing dist/

The dist/ folder is generated output — any change made there is overwritten on the next build. Always edit files under src/.

08 · Guide

Images & Assets

Where the template’s images live, and how to swap them for your own.

LocationUse forBehavior
public/images/Every image in the template — logos (logo-dark.svg, logo-light.svg), page artwork grouped by page (home/, about/, features/, blog/, …), and shared images in shared/Copied as-is, no processing; referenced by root-relative URL such as /images/home/hero.png
public/ (root)favicon.svg and favicon.icoCopied as-is to the site root

Replacing Images

Swap the file in place (keeping the same filename), or put your file in public/images/ and update the path where it’s set. Most image paths, with their width and height, live in the data files under src/data/:

javascriptsrc/data/home.js
export const hero = {
  heading: 'IT Solutions That Keep Your Business Grow',
  // …
  art: {
    image: { src: '/images/home/hero.png', width: 597, height: 685 },
    // …
  },
};

Blog post images are set in each post’s front matter (image, listImage, and media) in src/content/blog/. If your replacement has a different aspect ratio, update the width/height values too so the page doesn’t shift while loading.

Supported Formats & SVGs

Images are rendered with plain <img> tags, so any format the browser supports works — the template ships PNG, JPG, and SVG files. UI icons are not image files: they are inline SVGs drawn by src/components/Icon.astro (see Fonts & Icons), so they inherit color via currentColor.

Image Optimization

Because images are served from public/, the build does not resize or re-encode them — compress your images (for example to WebP or optimized JPG) before adding them. The sharp dependency is only used at build time to read image dimensions for the blog list layouts.

Rule of thumb

Keep new images in the matching public/images/<page>/ folder, reference them with a leading slash (/images/…), and always set width, height, and meaningful alt text.

09 · Guide

Fonts & Icons

Swapping typefaces and icon sets without touching every component.

Fontsource Fonts (Manrope, Inter, Outfit)

Techwave loads no fonts from Google Fonts or any other CDN — every font is self-hosted. Manrope (headings), Inter (buttons), and Outfit (the About page’s story tabs) come from the Fontsource npm packages and are imported per weight. Manrope and Inter are imported in the shared layout:

astrosrc/layouts/Layout.astro
import '@fontsource/manrope/400.css';
import '@fontsource/manrope/500.css';
import '@fontsource/manrope/600.css';
import '@fontsource/manrope/700.css';
import '@fontsource/inter/600.css';
import '@fontsource/inter/700.css';

To switch typeface, install its package (npm install @fontsource/<font>), replace these imports, and update the matching --font-heading / --font-button variable in src/styles/global.css. Outfit is imported directly in src/components/sections/about/StoryTabs.astro.

Local Fonts (Satoshi)

The body font, Satoshi, is self-hosted from public/fonts/satoshi/ (400, 500, and 700 weights) and declared with @font-face at the top of global.css. Layout.astro also preloads the 500 weight:

csssrc/styles/global.css
@font-face {
  font-family: 'Satoshi';
  src: url('/fonts/satoshi/satoshi-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

If you replace Satoshi, update the @font-face rules, the --font-body variable, and the <link rel="preload"> path in Layout.astro.

Icon Libraries

No icon library is installed. UI icons are inline SVGs defined in one component, src/components/Icon.astro, which holds a small set keyed by name — chevron-down, search, close, arrow-up, envelope, mobile, link, clock, heart, and social icons (facebook, facebook-circle, instagram, linkedin, linkedin-in, twitter, x-twitter, pinterest, google, vimeo, whatsapp). Decorative illustrations and feature icons are image files in public/images/.

Replacing & Adding Icons

Use an icon by name; extra attributes (such as width, height, or class) pass through to the <svg>, and the icon inherits the surrounding text color:

astro
<Icon name="envelope" width="16" height="16" />

To add an icon, open Icon.astro and add an entry to the icons object with the SVG’s viewBox and inner markup as body (set stroke: true for outline icons).

10 · Beginner Friendly

Content Editing

The fastest, lowest-risk way to make the site say what you want it to say.

New to code?

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

Page text in Techwave lives in data files, not in the page markup. Open the file in src/data/ named after the page (home.js, features.js, solutions.js, why-choose-us.js, pricing-page.js, about.js, careers.js, contact.js, forms.js for demo/sign-in/sign-up), find the section, and edit the text between the quotes:

javascriptsrc/data/home.js
// before
export const hero = {
  heading: 'IT Solutions That Keep Your Business Grow',
  text: 'Partner with a trusted provider delivering managed IT, secure networks, and expert technical support.',
  button: { label: 'Explore Solutions', href: '/solutions' },
  // …
};

// after
export const hero = {
  heading: 'Help Desk Support Your Team Can Count On',
  text: 'Fast, friendly IT support for small and growing businesses.',
  button: { label: 'Book a call', href: '/contact' },
  // …
};

Keep the quotes and commas intact. If a piece of text contains an apostrophe, use a curly one (’) as the existing copy does, or wrap the string in double quotes.

Menu links are kept in src/data/navigation.js and footer content (newsletter, tagline, social links, link columns, copyright) in src/data/footer.js, so you edit each label and URL once rather than hunting through every page. See Navigation for the full pattern.

Cards, Testimonials & Pricing

Repeating content blocks are driven by data rather than hand-written per card, so adding or removing an item is a matter of editing a list. Testimonials are in src/data/testimonials.js and the pricing plans (shown on every page with the pricing table) in src/data/pricing.js:

javascriptsrc/data/pricing.js
const features = ['Support', 'Free Updates', 'Custom Domain', 'Unlimited Storage', '12 Add-Ons'];

export const pricing = {
  heading: 'Plans and Pricing',
  periods: [
    { id: 'monthly', label: 'Monthly', plans: [plan('Free', '0'), plan('Basic', '19'), plan('Premium', '59', true), plan('Enterprises', '119')] },
    { id: 'yearly', label: 'Yearly', plans: [plan('Free', '0'), plan('Basic', '14'), plan('Premium', '39', true), plan('Enterprises', '109')] },
  ],
  // …
};

Each plan(name, amount, featured) call is one pricing card; the third argument highlights it. Change the shared features list, or the defaults inside the plan helper at the top of the file, to change what every card lists.

Blog Content & Contact Information

Blog posts are Markdown files in src/content/blog/, one per post, published at /<slug>. Edit the front matter and body directly; to add a post, copy an existing file and change its slug. The available front-matter fields are defined in src/content.config.js:

markdownsrc/content/blog/a-closer-look-at-connected-living.md
---
title: "A closer look at connected living"
slug: "a-closer-look-at-connected-living"
date: "2022-05-20T12:24:49"
excerpt: "Our most successful engagements have been …"
author: "techwave"        # key in src/data/authors.js
categories: ["Article", "Digital", "Technology"]
# also: updated, tags, image, listImage, likes,
# headerStyle ('hero' | 'classic'), format ('standard' | 'gallery' | 'audio' | 'video' | 'quote'), media
---

Authors are in src/data/authors.js, demo comments in src/data/comments.js, and the blog sidebar content in src/data/sidebar.js. The privacy policy and terms of use are Markdown files in src/content/legal/.

Contact details — office address, support email and phone, and social links — are in the enquiry.sidebar list in src/data/contact.js. Footer social links and the copyright line are in src/data/footer.js. The shipped email (hello@example.com) and phone number are placeholders; replace them with your own.

12 · Guide

Forms

What ships out of the box, and what still needs a backend.

Forms need somewhere to go

A contact or newsletter form in this template captures input in the browser, but submitting it to an email inbox, database, or mailing list requires a backend endpoint or a third-party service — this is not included by default. Techwave is not wired to any service: every form ships with action: '#', so submissions go nowhere until you set a real endpoint.

Contact Forms

The template has plain HTML forms with no JavaScript submit handler, so connecting one is a matter of setting its action URL in the data file:

FormComponentSet action in
Contact page enquiry formsections/contact/EnquiryForm.astrosrc/data/contact.js → enquiry.form.action
Book a Demo, Sign In, Sign Upui/LeadForm.astrosrc/data/forms.js → demo.form.action, signIn.form.action, signUp.form.action
Footer newsletterFooter.astrosrc/data/footer.js → newsletter.action
Blog comment reply formsections/post/PostComments.astroThe component’s action prop (defaults to '#')
javascriptsrc/data/contact.js
export const enquiry = {
  heading: 'Enquiry form',
  form: {
    action: 'https://formspree.io/f/your-form-id', // was '#'
    subjects: ['Subject', 'Astro', 'Shopify', 'Application'],
    submitLabel: 'Submit Form',
  },
  // …
};

The fields of the demo, sign-in, and sign-up forms are also defined in src/data/forms.js (name, label, type, required), so you can add or remove fields without editing markup. The sign-in and sign-up pages are front-end only — there is no authentication backend.

Newsletter Forms

The footer newsletter form is not pre-wired to any email provider. Set newsletter.action in src/data/footer.js to your provider’s form endpoint (Mailchimp, ConvertKit, Formspree, …); the form posts a single email field.

Form Validation

Required fields and email format are checked in the browser before submission using standard HTML attributes (required, type="email"), giving users immediate feedback without a round trip to a server. Validate again on the receiving end — browser checks alone can be bypassed.

Third-Party Form Services

If you’d rather not run your own backend, services like Formspree, Web3Forms, Getform, or Basin accept form submissions directly from static HTML and forward them to your email — typically a one-line change to the form’s action value in the data files above. If you deploy to Netlify, Netlify Forms can also capture them (add the data-netlify="true" attribute to the <form> tag in the component).

The header’s search overlay (src/components/SearchOverlay.astro) submits to /search, which doesn’t exist yet. Add a search page (for example with Pagefind) or remove the search button if you don’t need it.

13 · Guide

API & Data

Only relevant if your template fetches data from an external source — skip this section otherwise.

Techwave fetches no external data

The template calls no APIs and needs no API keys. All content is local: page copy and settings in src/data/*.js, and blog posts and legal pages in the Markdown content collections under src/content/, read at build time with Astro’s getCollection(). Everything below is general guidance in case you connect an API or headless CMS later.

API Configuration

If you add an API, read its URLs and keys from environment variables (see Configuration) rather than hard-coding them, so the same code can point at a staging or production API depending on environment:

env.env
PUBLIC_API_URL=https://example.com/api
PUBLIC_API_KEY=your_api_key
Never expose real credentials

The values above are placeholders. Keep real API keys out of version control, and prefer server-only variables (without the PUBLIC_ prefix) for anything sensitive.

Fetch Requests

javascript
const res = await fetch(`${import.meta.env.PUBLIC_API_URL}/products`, {
  headers: { Authorization: `Bearer ${import.meta.env.PUBLIC_API_KEY}` },
});
const data = await res.json();

Data Structures

The only structured data the template defines is its two content collections, validated with Zod schemas in src/content.config.js:

  • blog — title, slug, date (required); optional updated, excerpt, image, listImage; author (default 'techwave'), likes, categories, tags, headerStyle ('hero' | 'classic'), format ('standard' | 'gallery' | 'audio' | 'video' | 'quote'), and a media object (image, gallery, galleryNav, audio, video as a YouTube id, quote).
  • legal — title, updated, and variant ('privacy' | 'terms').

If you move posts to an external CMS, map its response onto these same fields so the existing layouts and listing pages keep working. A front-matter value that doesn’t match the schema fails the build with a message naming the file and field.

Error Handling

javascript
try {
  const res = await fetch(apiUrl);
  if (!res.ok) throw new Error(`Request failed: ${res.status}`);
  const data = await res.json();
} catch (err) {
  // show a fallback UI state instead of a blank page
  console.error(err);
}
14 · Guide

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. Pages that omit them fall back to the defaults in src/layouts/Layout.astro, and blog posts take theirs from front matter.

astro
<Layout
  title="Services – Techwave"
  description="Managed IT services and help desk support for growing teams."
  image="/images/og/services.jpg"  <!-- optional: Open Graph image path -->
>

Canonical URL, Open Graph & Twitter/X Cards

Already set inside Layout.astro’s <head> for every page, using the site value from astro.config.mjs to build absolute URLs:

astrosrc/layouts/Layout.astro
<link rel="canonical" href={canonical} />
<meta property="og:type" content={type} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:url" content={canonical} />
<meta property="og:image" content={ogImage} />
<meta name="twitter:card" content="summary_large_image" />

The default Open Graph image is /images/logo-dark.svg. Most social networks don’t render SVG previews, so add a 1200×630 JPG or PNG to public/images/ and change the image default in Layout.astro (or pass image per page). Blog posts set og:type to article and use their front-matter image as the preview, and their excerpt as the description.

Sitemap & Robots.txt

The template includes Astro’s official sitemap integration (@astrojs/sitemap), which generates sitemap-index.xml automatically at build time from the site value, leaving out the 404 page. No robots.txt is included — create public/robots.txt to control crawler access and point it at the sitemap:

textpublic/robots.txt
User-agent: *
Allow: /
Sitemap: https://techwave.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. The template ships no JSON-LD; add structured data in Layout.astro’s <head> for rich results (e.g. Organization or Article schema) where relevant to your content.

15 · Guide

Deployment

Platform-by-platform steps. Confirm your rendering mode first — it changes the build output you deploy.

Static vs. SSR — check this first

Techwave is a fully static Astro build (no adapter is installed): it produces plain HTML/CSS/JS in dist/ that any static host can serve. Only follow the SSR notes below if you later add a server adapter yourself — using the wrong instructions for your rendering mode is the most common deployment mistake.

Vercel

  1. Push the project to a GitHub, GitLab, or Bitbucket repository.
  2. In Vercel, choose Add New → Project and import that repository.
  3. Build command: npm run build · Output directory: dist (Astro static) — Vercel’s Astro preset detects this automatically in most cases.
  4. If you’ve added a .env file, add its variables under Project Settings → Environment Variables (the template itself needs none).
  5. Click Deploy.

Netlify

tomlnetlify.toml
[build]
  command = "npm run build"
  publish = "dist"

Connect the repository in the Netlify dashboard, confirm these build settings, add any environment variables you’ve introduced under Site configuration → Environment variables, and deploy. The template ships no netlify.toml; create one with the content above if you want the settings in the repository.

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. Because Techwave is static, ordinary shared hosting works — no Node.js is needed on the server. (Only if you later switch to SSR with an adapter would the host need to run node continuously.)

16 · Guide

Build & Production

What happens when you run build, and a checklist before you ship.

bash
npm run build     # validate content, bundle, and write dist/
npm run preview   # serve dist/ locally, exactly as it will run in production

Build Output

The build writes one static HTML page per route (including every blog post, listing page, and archive page), hashed CSS/JS bundles, the files from public/, and sitemap-index.xml to dist/. This folder is disposable and regenerated by every build — the template’s .gitignore already keeps it out of Git.

Environment Variables in Production

Techwave needs no environment variables out of the box. If you add some, note that 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 build locally and confirm it completes with no errors.
  • Run npm run preview and click through the main pages.
  • Replace https://techwave.example.com in astro.config.mjs with your real domain.
  • If you added a .env file, set every variable from it in your hosting platform’s dashboard.
  • Point every form action (contact.js, forms.js, footer.js) at a real endpoint instead of '#'.
  • Replace the placeholder contact email and phone in src/data/contact.js, the '#' social links in src/data/footer.js, and the copyright line.
  • Verify favicon, Open Graph image, and meta descriptions are your own, not the template defaults.
  • Add a /search page or remove the header search, and replace the demo blog posts and images.
17 · Reference

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 --version meets the requirement in Requirements, then run rm -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 (the template uses relative imports only — no path aliases).
Solution
Re-run npm install; check the number of ../ segments and that the path casing matches the file exactly, including the .astro or .js extension.

Images not loading

Cause
The path doesn’t match a file under public/ — usually a missing leading slash, an extra public/ in the path, or different filename casing.
Solution
Review Images & Assets — a file at public/images/home/hero.png is referenced as /images/home/hero.png. Filenames are case-sensitive on most hosts even if they work locally on Windows or macOS.

Styles not loading

Cause
A new page doesn’t render inside Layout (which imports global.css and the fonts), or a class added to a component isn’t styled because scoped styles only apply to markup in the same file.
Solution
Wrap the page in <Layout> (see Pages); put the CSS in the component that renders the element, or use :global() for styles that must reach a child component or Markdown content.

Blog post front-matter errors

Cause
A Markdown file in src/content/blog/ or src/content/legal/ is missing a required field or has a value the schema doesn’t allow (for example an unknown format), often after copying a post.
Solution
Read the error’s file and field name, compare against the schema in src/content.config.js (see Data Structures), and fix the front matter. Make sure every post’s slug is unique.

Build fails (but dev server works)

Cause
The dev server is more forgiving than build, which renders every route — every blog post, listing page, and archive — so a broken page you haven’t opened in dev can still 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 (if you’ve added any)

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 restart npm run dev — env changes aren’t hot-reloaded.

Deployment problems

Cause
Wrong output directory configured on the host, a Node.js version below 22.12.0 in the build environment, or (if you added any) environment variables set locally but not in the platform’s dashboard.
Solution
Re-check the build command (npm run build) and output folder (dist) against Deployment for your platform, set the platform’s Node.js version to 22 or later, and confirm every variable from .env is duplicated there.
18 · Reference

FAQ

Quick answers to the questions we hear most.

How do I install the template?

Extract techwave-astro-package.zip, open the techwave-astro folder inside it, run npm install, then start the dev server with npm run dev. The full walkthrough is in Getting Started.

Which Node.js version should I use?

Node 22.12.0 or later, as required by Astro 7 — see Requirements.

Do I need to know TypeScript or React?

No. Techwave is written in plain JavaScript and .astro components, with no React or other UI framework. The tsconfig.json only helps your editor understand Astro’s types. Most everyday edits are text changes in src/data/ and Markdown files.

How do I change colors?

Update the --color-* custom properties in src/styles/global.css — for example --color-accent for the coral buttons and labels — see Styling.

How do I change fonts?

Swap the Fontsource imports in Layout.astro (or the Satoshi @font-face rules in global.css) and update the corresponding --font-* variable — see Fonts & Icons.

How do I replace images?

Swap the file in public/images/ or update its path in the matching src/data/ file or post front matter — see Images & Assets.

How do I add a new page?

Add a file to src/pages/; the route is created automatically — see Pages. To add a blog post, add a Markdown file to src/content/blog/ instead.

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.

19 · Reference

Changelog

Every notable change, newest first. Add a new entry above the last one for each release.

Version 0.0.1[Release date]
  • AddedInitial release of the Techwave Astro template: home, features, solutions, why choose us, pricing, about, careers, contact, demo, sign-in, sign-up, legal, and 404 pages; a Markdown blog with 12 listing styles, five post formats, and author/category/tag/format archives; mega menu and mobile drawer; GSAP scroll animations, Swiper sliders, and an automatic sitemap.
Keeping this current

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.

20 · Reference

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 top

Contact support

Email hello@rnnstudio.com or reach us through our contact form.

Contact support

Support 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:

text
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