Editing the content — Findit Astro
All the words and images of the site live in src/content/. You edit plain JSON files — text in quotes, commas between
entries — and the site updates while npm run dev is running. No CMS is needed. (If you would rather manage content in
Sanity, Payload, Strapi or Directus, see Using a headless CMS.)
src/content/ site.json name, description, domain, navigation, contact details, footer, social links pages/home.json the copy of the home page pages/about.json …and of every other page sections.json copy of sections that appear on several pages (benefits, process, FAQ, facts, …) collections/*.json properties, agents, locations, categories, testimonials, posts, legal, team schemas.ts the fields each kind of item has, and which are requiredNot sure which file holds a piece of text? The page maps label every section of every page with its file.
Your details first
Section titled “Your details first”src/content/site.json holds what appears on every page:
| Field | Shown where |
|---|---|
site.name |
Logo alt text, browser title suffix, share cards |
site.title |
Browser title of the home page |
site.description |
Search results and share cards, for pages without their own description |
site.url |
Set this to your domain before publishing. Canonical links, share links, sitemap.xml and robots.txt are built from it |
navigation |
The menu in the header |
headerActions |
The two buttons in the header (the first one is filled) |
contact |
Address, phone numbers, email and opening hours — used on the Contact page and in the footer |
socials |
The social links in the footer |
footer |
The call-to-action above the footer, the two link columns, the newsletter texts and the copyright line ({year} becomes the current year) |
site.url is read by astro.config.mjs at build time, so restart npm run dev after changing it.
Page copy
Section titled “Page copy”One file per page in src/content/pages/. Each holds the sections of that page and a meta entry:
{ "meta": { "title": "About us", "description": "Findit connects buyers, sellers and renters with the right property." }, "hero": { "…": "…" }}title becomes the browser tab (“About us | Findit”) and description the text in search results and share cards (80–160
characters). Change what is inside the quotes and keep the field names — the sections read them by name. JSON has no
comments and no trailing commas; if the site stops building, that is usually why.
The Properties page’s meta also holds the titles and descriptions of the filter pages. {name} in them is replaced by
the location or category name: "Properties in {name}".
Collections
Section titled “Collections”src/content/collections/ holds the lists the site builds pages from:
| File | What it feeds |
|---|---|
properties.json |
The Properties list, one page per property, the filters, the home page (Featured, Latest) and each agent’s list |
agents.json |
The Agents page, one page per agent, the agent card on every property |
locations.json |
The location filter pages, the cities on the home page, the location of a property |
categories.json |
The category filter pages and the tabs of “Latest properties” |
posts.json |
The Blog, one page per post, “More Blog” |
testimonials.json |
The two tickers (desktop) and the carousel (phone and tablet) |
team.json |
The team grid on About |
legal.json |
Terms of Service and Privacy Policy, one page each (/legal/<slug>) |
The order of the items in the file is the order on the site. The home page shows the first five properties that have
"featured": true, the first six properties of a tab in “Latest properties”, and the three first posts; the numbers are in
FeaturedSection.astro, LatestSection.astro and BlogSection.astro. A property page ends with up to two more
properties in the same location and four in the same category; a post ends with up to three more posts of the same
category.
Adding a property
Section titled “Adding a property”Copy an existing entry, paste it below (with a comma between entries), and change the values:
{ "slug": "harbor-view-loft", "title": "Harbor View Loft", "propertyId": "55L120", "for": "sell", "featured": false, "category": "apartments", "agent": "steve-parker", "location": "brooklyn", "address": "12 Pier Street, Brooklyn, NY 11201", "price": 640000, "duration": "/Month", "image": "/images/property-harbor-view-loft.jpg", "gallery": [ "/images/property-harbor-view-loft-2.jpg", "/images/property-harbor-view-loft-3.jpg", "/images/property-harbor-view-loft-4.jpg", "/images/property-harbor-view-loft-5.jpg" ], "video": "https://www.youtube.com/watch?v=…", "description": [{ "type": "paragraph", "text": "**Harbor View Loft** is …" }], "features": [{ "type": "paragraph", "text": "…" }], "details": { "size": 120, "bedrooms": 2, "bathrooms": 2, "floor": "3", "additionalSpace": "Balcony", "furnishing": "Semi furnished", "ceilingHeight": 3, "constructionYear": "2015-01-01", "renovation": "2023-01-01" }, "utility": { "heating": "Central", "airCondition": "Yes", "fireplace": "-", "elevator": "Yes", "ventilation": "Yes", "intercom": "Yes", "windowType": "Aluminum frame", "cableTv": "Yes", "wifi": "Yes" }}What the fields mean: for is "sell" or "rent"; featured: true may put it in the home page’s Featured section;
category, agent and location are slugs from the other collections; price is in dollars and shown as $640,000;
duration is shown after the price of properties for rent only; gallery holds four more photos; video is an optional
YouTube link.
slug must be unique and URL-safe (lower case, words joined by -); it becomes the address
/property/harbor-view-loft. The page, its card everywhere, its place in the filters and its entry in sitemap.xml
appear by themselves — there is nothing else to register. Cards show the size under the name “Sqft”; the number is
whatever you enter (the demo uses square metres, and the property page says m2).
A location or category that no property uses is not listed: the home page shows only the cities that have properties, the filter card only the chips that lead somewhere. “No Location” and “Uncategory” are fallback items for properties without a real one; keep or delete them.
Adding an agent, location, category, post or team member
Section titled “Adding an agent, location, category, post or team member”| Add | Fields |
|---|---|
| Agent | slug, name, image (portrait, ratio about 0.7), address, bio, phone, mobile, whatsapp (digits, no +), email |
| Location | slug, name, image (used by the city cards on the home page) |
| Category | slug, name |
| Post | slug, title, category (any word; posts with the same one are shown as “More” under each other), date ("2026-05-16"), author, image, excerpt (the card text: the post’s first sentence), body |
| Team member | name, role, bio, photo |
| Testimonial | slug, name, photo, rating (1–5 stars), title, quote |
| Legal text | slug, title, description (search results), updated ("2023-11-16"), body |
An agent’s page lists every property whose agent is that agent’s slug, so a new agent needs no list of their own.
Removing an item
Section titled “Removing an item”Delete the entry (and its comma). Items refer to each other by slug: a property names its agent, location and
category, and the build stops with missing category, location or agent and the property’s slug when one of them
no longer exists. Update those properties, then build again.
What each field means
Section titled “What each field means”src/content/schemas.ts is the reference: every field, its type, and .optional() for the ones you can leave out. The
build validates your JSON against it and names the file, the item and the field when something is missing.
Rich text: descriptions, posts and legal texts
Section titled “Rich text: descriptions, posts and legal texts”A description, a post body or a legal text is a list of blocks:
"body": [ { "type": "heading", "text": "1. Information we collect" }, { "type": "paragraph", "text": "A paragraph with **bold text** and a [link](/contact) inside it." }, { "type": "list", "items": ["**First** item", "Second item"] }, { "type": "list", "ordered": true, "items": ["Step one", "Step two"] }]Bold text is wrapped in **double stars**, links are text, and \n inside a text is a line break. Property
descriptions and features use paragraphs; posts too; legal texts use headings and lists as well.
The hero video
Section titled “The hero video”The video on the home page is hero.video in src/content/pages/home.json: src is a file or a web address, poster the
picture shown before it plays. The demo plays a clip straight from Pexels; to use your own, put an MP4 in public/videos/
and set "src": "/videos/tour.mp4". Nothing is downloaded until a visitor presses play.
Images
Section titled “Images”- Put the file in
src/assets/images/. - Refer to it in the content as
/images/<file>.
Astro resizes each photo, converts it to a modern format and sets the width and height for you, so the page never
jumps while loading. Use photos at least as wide as they appear (property and post photos: 1400 px or more, cards:
1200 px, portraits: 800 px), .jpg for photos and .png when you need transparency. Keep the demo’s aspect ratios —
the layout crops to fit.
Files in public/ are served untouched, which is what the icons and the share image need:
| File | What it is |
|---|---|
public/icon.svg, public/apple-icon.png |
The icon in the browser tab and on a phone’s home screen |
public/opengraph-image.png |
The picture shown when someone shares a link (2400 × 1260; 1200 × 630 or larger) |
Its description for screen readers is shareImageAlt in src/layouts/Layout.astro. Every page uses this image when
shared, except the property, agent and post pages, which share their own image.
The search-result description of a property is the first sentence of its description, of an agent the first sentence of
their bio, and of a post its excerpt — start each with a real sentence.
Text that is not in content/
Section titled “Text that is not in content/”Interface words that never change per site — “Beds”, “Baths”, “Sqft”, form messages — live with the components in
src/design-system/. Search for the phrase and you will find it. Everything a visitor reads as your words is in
src/content/.
After editing
Section titled “After editing”npm run check && npm run buildTogether they confirm every content file matches its schema and every page, link and image still resolves. See Going live for the rest of the checklist.