TSX Component Development Guide

This guide provides comprehensive standards for creating custom TSX components for ColivingLiguria pages, ensuring consistency, maintainability, and aesthetic excellence.

IMPORTANT

Read this document before creating any new custom page component

This guide is based on proven patterns from NewHome.tsx and ElectricalSystem.tsx. Following these standards ensures your pages maintain the siteโ€™s visual identity and professional quality.


Table of Contents

  1. Color Palette & Theme
  2. Component Structure
  3. Styling Conventions
  4. Common Patterns
  5. Responsive Design
  6. Accessibility
  7. Code Examples
  8. Internationalization (Bilingual Support)
  9. Page Layout Configuration
  10. Code Examples

Page Layout Configuration

IMPORTANT

No Backlinks or Graph View on TSX Pages

Custom TSX pages (like the Homepage) are designed to be standalone experiences. You MUST disable the standard Quartz sidebar features (Backlinks, Graph View, Explorer) for these pages to prevent clutter and maintain visual focus.

How to disable in quartz.layout.tsx: Ensure your custom pageโ€™s layout configuration excludes Component.Backlinks(), Component.Graph(), and Component.Explorer().

Color Palette & Theme

Core Color Variables

Always use CSS variables - never hardcode colors. Our palette is defined in quartz.config.ts and available via CSS variables:

// Light Mode Colors
--light: "#F7F5F3"        // Warm Alabaster (backgrounds)
--lightgray: "#E5E0D8"    // Light Sand (secondary backgrounds)
--gray: "#948C84"         // Stone (muted text, borders)
--darkgray: "#4E4B42"     // Bark (secondary text)
--dark: "#2C2A24"         // Deep Peat (primary text)
--secondary: "#4A6741"    // Deep Moss Green (CTAs, highlights)
--tertiary: "#A67B5B"     // Raw Sienna/Clay (accents)
 
// Dark Mode Colors (auto-transforms)
--light: "#0F0E0B"        // Deep Earth Black
--lightgray: "#26231E"    // Dark Soil
--gray: "#857F75"         // Warm Stone
--darkgray: "#D6D1C9"     // Bone/Light Sand
--dark: "#F0ECE6"         // Off-white
--secondary: "#8FA876"    // Light Moss/Sage
--tertiary: "#D4A373"     // Buff/Sandstone

Usage Examples

// โœ… CORRECT - Using CSS variables
<div style="background: var(--lightgray); color: var(--dark);">
    <h2 style="color: var(--secondary);">Title</h2>
</div>
 
// โŒ WRONG - Hardcoded colors
<div style="background: #E5E0D8; color: #2C2A24;">
    <h2 style="color: #4A6741;">Title</h2>
</div>

Color Application Rules

ElementColor VariableUsage
Page Backgroundvar(--light)Main page background
Section Background (Alt)var(--lightgray)Alternating sections for visual rhythm
Cards/Boxeswhite in light mode, var(--lightgray) in darkElevated content containers
Primary Textvar(--dark)Headings, important text
Secondary Textvar(--gray)Body text, descriptions
Bordersvar(--lightgray)Subtle borders (2px max)
CTAs/Buttonsvar(--secondary) backgroundPrimary action buttons
Highlightsvar(--secondary) or var(--tertiary)Emphasis, badges, icons

TIP

Dark Mode Compatibility

Never use pure white or #FFFFFF for backgrounds - use var(--light). This ensures proper dark mode transformation.

CAUTION

CRITICAL: Light/Dark Mode Color Correspondence Validation

You MUST scrupulously verify that all colors work correctly in BOTH light mode and dark mode. Each color variable transforms automatically, and you need to ensure:

  1. Text remains readable in both modes
  2. Background/foreground contrast is sufficient in both modes
  3. Accent colors (--secondary, --tertiary) are visible against their backgrounds in both modes

Before publishing any component, test it in:

  • Light mode (default)
  • Dark mode (toggle in browser)

Palette-Only Rule

WARNING

ONLY Use Palette Colors - NEVER Custom Colors

You are STRICTLY PROHIBITED from using any colors outside the defined palette. This means:

  • โœ… var(--light), var(--lightgray), var(--gray), var(--darkgray), var(--dark)
  • โœ… var(--secondary), var(--tertiary)
  • โœ… white (only for card backgrounds in light mode)
  • โŒ NO custom hex codes like #FF5733 or #123456
  • โŒ NO custom RGB values like rgb(255, 100, 50)
  • โŒ NO named colors like red, blue, green

If you need a new color, request an update to the palette in quartz.config.ts first.

Light/Dark Mode Color Correspondence Table

This table shows how each color variable transforms between modes:

VariableLight ModeDark ModePurpose
--lightF7F5F3 (Warm Alabaster)0F0E0B (Deep Earth Black)Backgrounds
--lightgrayE5E0D8 (Light Sand)26231E (Dark Soil)Alt backgrounds, borders
--gray948C84 (Stone)857F75 (Warm Stone)Secondary text
--darkgray4E4B42 (Bark)D6D1C9 (Bone)Secondary text
--dark2C2A24 (Deep Peat)F0ECE6 (Off-white)Primary text
--secondary4A6741 (Deep Moss Green)8FA876 (Light Moss)CTAs, buttons
--tertiaryA67B5B (Raw Sienna)D4A373 (Buff)Accents

Notice: The correspondence is designed so that light mode backgrounds become dark mode backgrounds, and light mode text becomes dark mode text. Always verify your component respects this mapping.


Component Structure

File Organization

Every custom page component requires two files:

quartz/
โ”œโ”€โ”€ components/
โ”‚   โ”œโ”€โ”€ YourComponent.tsx          // Component logic
โ”‚   โ””โ”€โ”€ styles/
โ”‚       โ””โ”€โ”€ yourcomponent.scss     // Component styles

Basic Component Template

import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
import style from "./styles/yourcomponent.scss"
 
export default (() => {
    const YourComponent: QuartzComponent = ({ displayClass }: QuartzComponentProps) => {
        return (
            <div class={`your-component-page ${displayClass ?? ""}`}>
                {/* Content goes here */}
            </div>
        )
    }
 
    YourComponent.css = style
    return YourComponent
}) satisfies QuartzComponentConstructor

Registering the Component

  1. Add to components/index.ts:
// Import
import { default as YourComponent } from "./YourComponent"
 
// Export
export {
  // ... other exports
  YourComponent,
}
  1. Create content routing page:
---
title: Your Page Title
---

The component is automatically rendered based on matching routes.


Styling Conventions

SCSS Best Practices

Use Nested Selectors

.your-component-page {
  width: 100%;
  max-width: 100%;
  margin: 0;
  padding: 0;
 
  section {
    padding: 4rem 2rem;
    max-width: 1200px;
    margin: 0 auto;
 
    @media (max-width: 768px) {
      padding: 2rem 1rem;
    }
  }
}

Consistent Spacing Scale

Use multiples of 0.5rem for consistent spacing:

// Spacing scale
// 0.5rem, 1rem, 1.5rem, 2rem, 2.5rem, 3rem, 4rem, 6rem
 
.card {
  padding: 2rem;           // Standard card padding
  margin-bottom: 2rem;     // Standard vertical spacing
  gap: 1.5rem;            // Grid/flex gaps
}
 
.section {
  padding: 4rem 2rem;      // Section vertical/horizontal padding
}

Typography Hierarchy

h1 {
  font-size: 3rem;             // Hero titles
  line-height: 1.2;
  font-weight: bold;
 
  @media (max-width: 768px) {
    font-size: 2rem;
  }
}
 
h2 {
  font-size: 2.5rem;           // Section titles
  margin: 0 0 1rem 0;
 
  @media (max-width: 768px) {
    font-size: 2rem;
  }
}
 
h3 {
  font-size: 1.8rem;           // Subsection titles
  margin: 0 0 1rem 0;
}
 
p {
  font-size: 1rem;             // Body text
  line-height: 1.7;            // Comfortable reading
  color: var(--gray);
}

Border Radius Standards

// Border radius scale
border-radius: 8px;      // Small elements (badges, tags)
border-radius: 12px;     // Medium elements (small cards)
border-radius: 16px;     // Standard cards
border-radius: 24px;     // Large cards, sections
border-radius: 50px;     // Pills, buttons

Box Shadow Standards

// Subtle elevation
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
 
// Medium elevation
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
 
// Strong elevation (cards)
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
 
// Colored shadows (use sparingly)
box-shadow: 0 8px 24px rgba(74, 103, 65, 0.15);  // Secondary color shadow

Common Patterns

Hero Section

<section class="hero">
    <div class="hero-content">
        <div class="hero-badge">โœจ Featured Project</div>
        <h1>Your Amazing Title</h1>
        <p class="hero-subtitle">
            Compelling subtitle that explains what this page is about.
        </p>
        <div class="cta-group">
            <a href="/link" class="cta-button primary">Primary Action</a>
            <a href="/link" class="cta-button secondary">Secondary Action</a>
        </div>
    </div>
</section>

SCSS:

.hero {
  text-align: center;
  padding: 6rem 2rem 4rem;
  background: linear-gradient(135deg, var(--lightgray) 0%, var(--light) 100%);
 
  .hero-badge {
    display: inline-block;
    background: var(--secondary);
    color: white;
    padding: 0.5rem 1.5rem;
    border-radius: 50px;
    font-size: 0.9rem;
    font-weight: 600;
    margin-bottom: 1.5rem;
  }
 
  h1 {
    font-size: 3rem;
    color: var(--dark);
    margin: 0 0 1rem 0;
    line-height: 1.2;
  }
 
  .hero-subtitle {
    font-size: 1.2rem;
    color: var(--gray);
    max-width: 800px;
    margin: 0 auto 2rem;
    line-height: 1.7;
  }
 
  .cta-group {
    display: flex;
    gap: 1rem;
    justify-content: center;
    flex-wrap: wrap;
  }
 
  .cta-button {
    padding: 1rem 2rem;
    border-radius: 50px;
    text-decoration: none;
    font-weight: 600;
    transition: transform 0.2s, box-shadow 0.2s;
 
    &:hover {
      transform: translateY(-2px);
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    }
 
    &.primary {
      background: var(--secondary);
      color: white;
    }
 
    &.secondary {
      background: white;
      color: var(--secondary);
      border: 2px solid var(--secondary);
    }
  }
}

Grid Layouts

<section class="features-section">
    <h2 class="section-title">Key Features</h2>
    <div class="features-grid">
        <div class="feature-card">
            <div class="feature-icon">โšก</div>
            <h3>Feature Title</h3>
            <p>Feature description goes here.</p>
        </div>
        {/* Repeat for each feature */}
    </div>
</section>

SCSS:

.features-section {
  .section-title {
    text-align: center;
    font-size: 2.5rem;
    color: var(--dark);
    margin: 0 0 3rem 0;
  }
 
  .features-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 2rem;
 
    @media (max-width: 768px) {
      grid-template-columns: 1fr;
    }
 
    .feature-card {
      background: white;
      border-radius: 16px;
      padding: 2rem;
      border: 2px solid var(--lightgray);
      transition: transform 0.3s, box-shadow 0.3s;
 
      &:hover {
        transform: translateY(-5px);
        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
      }
 
      .feature-icon {
        font-size: 3rem;
        margin-bottom: 1rem;
      }
 
      h3 {
        color: var(--dark);
        margin: 0 0 1rem 0;
        font-size: 1.5rem;
      }
 
      p {
        color: var(--gray);
        line-height: 1.6;
        margin: 0;
      }
    }
  }
}

Highlighted Info Boxes

<div class="info-box">
    <div class="info-header">
        <div class="info-icon">๐Ÿ’ก</div>
        <h3>Important Information</h3>
    </div>
    <p>Your informational content here.</p>
</div>

SCSS:

.info-box {
  background: var(--lightgray);
  border-radius: 16px;
  padding: 2rem;
  border-left: 4px solid var(--secondary);
  margin: 2rem 0;
 
  .info-header {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1rem;
 
    .info-icon {
      font-size: 2rem;
    }
 
    h3 {
      margin: 0;
      color: var(--dark);
    }
  }
 
  p {
    margin: 0;
    color: var(--gray);
    line-height: 1.7;
  }
}

Alternating Background Sections

<section class="section-light">
    {/* Content */}
</section>
 
<section class="section-gray">
    {/* Content */}
</section>
 
<section class="section-light">
    {/* Content */}
</section>

SCSS:

.section-light {
  background: var(--light);
  padding: 4rem 2rem;
}
 
.section-gray {
  background: var(--lightgray);
  padding: 4rem 2rem;
}

Responsive Design

Breakpoints

Use these standard breakpoints:

// Mobile
@media (max-width: 480px) {
  // Stacked layouts, larger touch targets
}
 
// Tablet
@media (max-width: 768px) {
  // Most responsive adjustments happen here
  grid-template-columns: 1fr;  // Single column grids
  padding: 2rem 1rem;          // Reduced padding
  font-size: 2rem;             // Smaller headings
}
 
// Desktop
@media (min-width: 769px) {
  // Default desktop styles
}

Mobile-First Pattern

// Start with mobile styles
.card {
  padding: 1rem;
  font-size: 1rem;
}
 
// Add desktop enhancements
@media (min-width: 769px) {
  .card {
    padding: 2rem;
    font-size: 1.1rem;
  }
}

---

## Internationalization (Bilingual Support)

> [!IMPORTANT]
> 
> **All New Pages MUST Be Bilingual (English & Italian)**
>
> Every custom TSX page must support both English and Italian. We use a CSS-based toggle system where the `<html>` tag receives a `data-lang="en"` or `data-lang="it"` attribute.

### How It Works

We toggle visibility using CSS classes:
- `.lang-en`: Visible when `data-lang="en"` (Hidden when "it")
- `.lang-it`: Visible when `data-lang="it"` (Hidden when "en")

### The `Translate` Helper Component

To make this easy AND reusable, we use a helper component `Translate`.

**Import:**
```tsx
import Translate from "./Translate"

Usage:

// Simple Text
<p>
  <Translate 
     en="Welcome to our community." 
     it="Benvenuti nella nostra comunitร ." 
  />
</p>
 
// Inside Headers
<h2>
  <Translate 
     en="Our Features" 
     it="Le Nostre Caratteristiche" 
  />
</h2>
 
// Inside Links
<a href="/apply">
  <Translate 
     en="Apply Now" 
     it="Candidati Ora" 
  />
</a>

Manual Implementation (Raw Spans)

If you cannot use the helper for some reason (e.g. complex nested HTML), use the raw spans:

<p>
    <span class="lang-en">English text here.</span>
    <span class="lang-it">Testo italiano qui.</span>
</p>

Accessibility

Semantic HTML

// โœ… CORRECT - Semantic structure
<section class="features">
    <h2>Features</h2>
    <article class="feature-card">
        <h3>Feature Title</h3>
        <p>Description</p>
    </article>
</section>
 
// โŒ WRONG - Generic divs everywhere
<div class="features">
    <div>Features</div>
    <div class="feature-card">
        <div>Feature Title</div>
        <div>Description</div>
    </div>
</div>
// โœ… CORRECT - Descriptive link text
<a href="/properties/casa-del-forno">Explore Casa del Forno โ†’</a>
 
// โŒ WRONG - Generic "click here"
<a href="/properties/casa-del-forno">Click here</a>

CRITICAL

Internal links in TSX components are CASE-SENSITIVE!

Quartz generates URLs that preserve the original casing of file and folder names. You MUST match the exact path casing or links will result in 404 errors.

// โœ… CORRECT - Match folder/file casing exactly
<a href="/Advertising/Offers/Internship-Offer">Internship Offer</a>
<a href="/Rules/Policies/Standard-Visa-Procedure">Standard Visa Procedure</a>
<a href="/Financials/Business-Segments/Visa-Consultancy/Premium-Visa-Assistance">Premium Visa Assistance</a>
 
// โŒ WRONG - Lowercase will cause 404
<a href="/advertising/offers/internship-offer">Internship Offer</a>
<a href="/rules/policies/standard-visa-procedure">Standard Visa Procedure</a>

How to derive the correct URL:

  1. Find the file in content/: e.g., content/Advertising/Offers/Internship Offer.md
  2. Preserve folder casing: Advertising, Offers stay capitalized
  3. Replace spaces with hyphens: Internship Offer โ†’ Internship-Offer
  4. Remove .md extension: Final link is /Advertising/Offers/Internship-Offer
File PathCorrect URL
content/Advertising/Offers/Work with Us.md/Advertising/Offers/Work-with-Us
content/Rules/Policies/Standard Visa Procedure.md/Rules/Policies/Standard-Visa-Procedure
content/Financials/Business Segments/Visa Consultancy/Visa Consultancy.md/Financials/Business-Segments/Visa-Consultancy/Visa-Consultancy

Internal Linking Requirements

IMPORTANT

Link to Related Content as Much as Possible

Every time you mention content that exists in another note or page, you MUST link to that page. This creates a well-connected knowledge network and improves navigation.

Rules:

  1. Maximize links: If content exists elsewhere, link to it
  2. Verify links work: Test every link after creating it
  3. Use correct paths: Follow case-sensitivity rules above
  4. Descriptive text: Use meaningful link text, not โ€œclick hereโ€

Link whenever you mention:

Content TypeExampleLink Requirement
Propertiesโ€Casa del Fornoโ€โœ… MUST link to Casa del Forno
Apartmentsโ€Sub 5โ€โœ… MUST link to Sub 5
Roomsโ€Private Double Bedroomโ€โœ… MUST link to room page
Technical Systemsโ€Hydraulic Systemโ€โœ… MUST link to system page
Policiesโ€Standard Visa Procedureโ€โœ… MUST link to policy
People/Rolesโ€Volunteersโ€โœ… SHOULD link to relevant offer
General conceptsโ€Colivingโ€Optional

Before publishing, verify each link:

  • Path is correct (case-sensitive, hyphens for spaces)
  • Link works (test by clicking in preview)
  • Target page exists (no 404 errors)
  • Link text is descriptive (not โ€œclick hereโ€)

Examples

// โœ… CORRECT - Rich linking
<p>
    Our <a href="/Houses/Chiappella/Properties/Casa-del-Forno/Casa-del-Forno">Casa del Forno</a> property 
    features three apartments: <a href="/Houses/Chiappella/Properties/Casa-del-Forno/Sub-5/Sub-5">Sub 5</a> 
    (8 people), <a href="/Houses/Chiappella/Properties/Casa-del-Forno/Sub-6/Sub-6">Sub 6</a> (4 people), 
    and <a href="/Houses/Chiappella/Properties/Casa-del-Forno/Sub-7/Sub-7">Sub 7</a> (5 people).
</p>
 
// โŒ WRONG - Missing links
<p>
    Our Casa del Forno property features three apartments: Sub 5 (8 people), 
    Sub 6 (4 people), and Sub 7 (5 people).
</p>

TIP

Finding the Correct Path

Use the file explorer or search in your editor to find the exact file path, then convert it to a URL:

  1. Remove content/ prefix
  2. Replace spaces with hyphens
  3. Remove .md extension
  4. Preserve original folder casing

Color Contrast

CRITICAL

TEXT MUST ALWAYS BE READABLE

It happens far too often that text is placed on a background where it is not sufficiently readable. You MUST carefully verify that when you pair text color with a textbox/card/section background, the contrast is sufficient for comfortable reading.

Common Mistakes to AVOID:

  • Light gray text on light background โ†’ UNREADABLE
  • Dark text on dark background โ†’ UNREADABLE
  • Colored text on similarly-colored background โ†’ UNREADABLE

If in doubt, increase the contrast!

Minimum Contrast Ratios

Ensure minimum 4.5:1 contrast ratio for body text:

// โœ… CORRECT - High contrast
color: var(--dark);           // #2C2A24 on var(--light) #F7F5F3 = 11.8:1
background: var(--light);
 
// โš ๏ธ CHECK - Medium contrast (still acceptable)
color: var(--gray);           // #948C84 on var(--light) #F7F5F3 = 4.8:1
background: var(--light);
 
// โŒ WRONG - Low contrast (UNREADABLE!)
color: var(--lightgray);      // Too low contrast
background: var(--light);

Safe Color Pairings

Use these proven combinations for readable text:

BackgroundText ColorContrastStatus
var(--light)var(--dark)11.8:1โœ… Excellent
var(--light)var(--gray)4.8:1โš ๏ธ Acceptable
var(--lightgray)var(--dark)Highโœ… Excellent
var(--secondary)whiteHighโœ… Excellent (buttons)
var(--secondary)var(--light)Highโœ… Excellent (buttons)
var(--tertiary)var(--dark)Highโœ… Good (accents)

Dangerous Pairings to AVOID

// โŒ NEVER DO THIS
color: var(--lightgray);
background: var(--light);        // Almost invisible!
 
// โŒ NEVER DO THIS
color: var(--gray);
background: var(--lightgray);    // Very hard to read!
 
// โŒ NEVER DO THIS (in dark mode)
color: var(--darkgray);
background: var(--lightgray);    // Check dark mode!

WARNING

Always Test in Both Modes

A color combination that works in light mode may fail in dark mode and vice versa. Test every text/background pairing in BOTH modes before publishing.


Code Examples

Complete Mini Component

// YourComponent.tsx
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
import style from "./styles/yourcomponent.scss"
 
export default (() => {
    const YourComponent: QuartzComponent = ({ displayClass }: QuartzComponentProps) => {
        return (
            <div class={`your-component-page ${displayClass ?? ""}`}>
                
                {/* Hero */}
                <section class="hero">
                    <div class="hero-content">
                        <h1>Welcome to Our Page</h1>
                        <p class="subtitle">Discover amazing things here.</p>
                    </div>
                </section>
 
                {/* Features */}
                <section class="features">
                    <h2 class="section-title">What We Offer</h2>
                    <div class="features-grid">
                        <div class="feature-card">
                            <div class="icon">๐ŸŽฏ</div>
                            <h3>Precision</h3>
                            <p>Carefully crafted experiences.</p>
                        </div>
                        <div class="feature-card">
                            <div class="icon">โšก</div>
                            <h3>Speed</h3>
                            <p>Lightning-fast performance.</p>
                        </div>
                        <div class="feature-card">
                            <div class="icon">๐Ÿ›ก๏ธ</div>
                            <h3>Security</h3>
                            <p>Your safety is our priority.</p>
                        </div>
                    </div>
                </section>
 
            </div>
        )
    }
 
    YourComponent.css = style
    return YourComponent
}) satisfies QuartzComponentConstructor
// yourcomponent.scss
@use "../../styles/variables.scss" as *;
 
.your-component-page {
  width: 100%;
  max-width: 100%;
  margin: 0;
  padding: 0;
 
  section {
    padding: 4rem 2rem;
    max-width: 1200px;
    margin: 0 auto;
 
    @media (max-width: 768px) {
      padding: 2rem 1rem;
    }
  }
 
  // Hero
  .hero {
    text-align: center;
    background: linear-gradient(135deg, var(--lightgray) 0%, var(--light) 100%);
 
    h1 {
      font-size: 3rem;
      color: var(--dark);
      margin: 0 0 1rem 0;
 
      @media (max-width: 768px) {
        font-size: 2rem;
      }
    }
 
    .subtitle {
      font-size: 1.2rem;
      color: var(--gray);
      max-width: 600px;
      margin: 0 auto;
    }
  }
 
  // Features
  .features {
    background: var(--light);
 
    .section-title {
      text-align: center;
      font-size: 2.5rem;
      color: var(--dark);
      margin: 0 0 3rem 0;
    }
 
    .features-grid {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 2rem;
 
      @media (max-width: 768px) {
        grid-template-columns: 1fr;
      }
 
      .feature-card {
        background: white;
        border-radius: 16px;
        padding: 2rem;
        text-align: center;
        border: 2px solid var(--lightgray);
 
        .icon {
          font-size: 3rem;
          margin-bottom: 1rem;
        }
 
        h3 {
          color: var(--dark);
          margin: 0 0 0.5rem 0;
        }
 
        p {
          color: var(--gray);
          margin: 0;
        }
      }
    }
  }
}

Common Pitfalls & Troubleshooting

Problem: Component Created But Page Shows Only Title

Symptom: Your TSX component exists, builds successfully, but the page only shows the title with empty content below.

Cause: Component not registered in quartz.layout.tsx routing configuration.

Solution: Add your component to the layout configuration file.

Step-by-Step Fix

  1. Open quartz.layout.tsx in the project root

  2. Add ConditionalRender for your component in the beforeBody array:

Component.ConditionalRender({
  component: Component.YourComponent(),
  condition: (page) => page.fileData.slug?.toLowerCase().endsWith("your-page-slug") ?? false,
}),
  1. Add exclusions for standard page elements (ArticleTitle, ContentMeta, TagList):
// In ArticleTitle condition (around line 49)
slug.endsWith("your-page-slug")
 
// In ContentMeta condition (around line 77)  
slug.endsWith("your-page-slug")
 
// In TagList condition (around line 95)
slug.endsWith("your-page-slug")
  1. Complete example:
// In quartz.layout.tsx, around line 48
Component.ConditionalRender({
  component: Component.ArticleTitle(),
  condition: (page) => {
    const slug = page.fileData.slug?.toLowerCase() ?? ""
    return !(
      slug === "index" ||
      slug.endsWith("digital-nomad-offer") ||
      slug.endsWith("volunteer-offer") ||
      slug.endsWith("your-page-slug")  // ADD THIS
    )
  },
}),
 
// Later in beforeBody array, around line 140
Component.ConditionalRender({
  component: Component.YourComponent(),
  condition: (page) => page.fileData.slug?.toLowerCase().endsWith("your-page-slug") ?? false,
}),
  1. Rebuild: npx quartz build

Why This Happens

Quartz uses conditional rendering to determine which components display on which pages. Without a ConditionalRender entry, your component never gets invoked, even though it exists and is imported.

The exclusions (ArticleTitle, etc.) prevent standard page chrome from appearing on your custom component pages, giving you full control over the layout.


Checklist Before Publishing

Use this checklist every time you create a new page component:

Colors & Contrast

  • Palette Only: All colors use CSS variables (no hardcoded hex, RGB, or named colors)
  • Dark Mode Tested: Component tested in dark mode (toggle browser)
  • Light Mode Tested: Component tested in light mode
  • Text Readable: All text has sufficient contrast against its background
  • No White Backgrounds: No pure white or #FFFFFF for backgrounds

Layout & Design

  • Responsive: Tested on mobile (< 768px) and desktop
  • Spacing: Uses consistent spacing scale (0.5rem multiples)
  • Typography: Proper hierarchy (h1 > h2 > h3 > p)
  • Links Correct: All internal links use correct case-sensitive paths
  • Links Verified: Each link tested and working
  • Maximum Linking: All related content mentioned is linked
  • Semantic HTML: Uses proper HTML elements (section, article, etc.)
  • Descriptive Links: No โ€œclick hereโ€ links

Technical

  • Registered: Component added to components/index.ts
  • Styled: SCSS file created in styles/ folder
  • Tested: Build completes without errors (npx quartz build)

Quick Reference

CSS Variables Cheatsheet

// Backgrounds
var(--light)         // Main page background
var(--lightgray)     // Alt sections
white                // Elevated cards (light mode)
 
// Text
var(--dark)          // Primary headings
var(--darkgray)      // Secondary headings
var(--gray)          // Body text
 
// Interactive
var(--secondary)     // Buttons, CTAs, links
var(--tertiary)      // Accents, highlights
 
// Borders
var(--lightgray)     // Most borders (2px max)
var(--secondary)     // Emphasized borders (left border, etc.)

Common Class Patterns

.section-title       // Centered, 2.5rem section titles
.hero               // Full-width hero sections
.cta-button         // Call-to-action buttons
.feature-card       // Grid item cards
.info-box           // Highlighted information boxes

Resources

  • Reference Components: NewHome.tsx, ElectricalSystem.tsx
  • Color Palette: quartz.config.ts
  • Markdown Guide: Markdown Style Guide.md
  • Build Command: npx quartz build

Remember: Consistency is key. When in doubt, reference existing components and follow established patterns.