Astro
Tailwind CSS
TypeScript
Nano Stores
Property Tailwind Astro Template is built with Astro and Tailwind CSS.
This theme is ready to use and you can fully customise it to suit your requirements.
To customise it you should be comfortable with Astro components, Tailwind CSS and plain TypeScript. No UI framework (React, Vue, Svelte) is used anywhere — every interactive piece is a plain <script> talking to a nanostore.
|—
public|—
images|—
favicon.ico|—
src|—
assets|—
components|—
content|—
data|—
layouts|—
lib|—
pages|—
stores|—
styles|—
types|—
content.config.ts|—
astro.config.mjs|—
package.json|—
tsconfig.jsonnpm installRequires Node.js 22.12 or newer, which is what Astro 7 expects.
npm run devServes the site on http://localhost:4321 with hot reloading.
npm run buildPrerenders every route into dist/ as plain HTML, CSS and a little JS.
npm run previewServes dist/ exactly as it will be deployed, base path included.
npm run checkRuns astro check over .astro and .ts files.
src/styles/global.css
Tailwind v4 has no tailwind.config.ts. Every design token lives in the @theme block — colours are --color-*, the container widths are --container-*, shadows are --shadow-*. Edit them there and every utility updates.
@theme {
--color-primary: #2f73f2;
--color-midnight_text: #102d47;
--color-darkmode: #0c121e;
}src/styles/global.css
Dark mode is a class on <html>, declared with @custom-variant. The pre-paint script in BaseLayout.astro reads localStorage and sets the class before the first frame, so there is no flash.
@custom-variant dark (&:where(.dark, .dark *));src/components/layout/Logo.astro
Two images, one for each theme. Replace the files in public/images/logo/ or point the component somewhere else. Paths go through asset() so the base path is applied automatically.
<img src={asset('/images/logo/logo.svg')} class="dark:hidden" />astro.config.mjs
The font is loaded by Astro’s built-in Fonts API — no <link> tags and no font CSS to manage. Change the name and weights here and the --font-dm-sans variable follows.
fonts: [{
provider: fontProviders.fontsource(),
name: 'DM Sans',
cssVariable: '--font-dm-sans',
weights: [400, 500, 700]
}]astro.config.mjs
The site is served from the domain root, so no base path is set. If you ever need to host under a subdirectory, add base and everything adjusts — nothing hardcodes a leading slash, because all URLs go through asset() and url() in src/lib/paths.ts. SITE_URL must be set at build time or canonical tags are omitted.
site: process.env.SITE_URL,
// base: '/subdir', // only for subdirectory hostingsrc/data/propertydata.json
Listings are a flat JSON array imported at build time. Each entry generates its own prerendered detail page from src/pages/nekretnina/[slug].astro via getStaticPaths().
{ "slug": "modern-apartment", "property_title": "Modern Appartment", ... }src/content/blogs/*.md
Markdown with frontmatter, loaded by a content collection with a Zod schema (src/content.config.ts). Add a file and the route appears; a missing or misspelled frontmatter field fails the build instead of rendering blank.
---
title: Exploring Luxury Real Estate Markets
date: 2025-11-08
coverImage: /images/tabbar/tab-1.jpg
author: silicaman
authorImage: /images/blog/silicaman.jpg
---