Skip to content

About

Find fresh, local produce and artisanal goods in your area with market hours, locations, and vendor information.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

FarmerMarket.us

FarmerMarket.us

MadeWithSvelte.com shield

A comprehensive directory of farmer's markets across America built with SvelteKit, featuring state-based filtering, interactive maps, detailed market information, and comprehensive SEO optimization.


✨ Features

  • πŸͺ Farmer's Market Directory: Comprehensive listings of 1000+ farmer's markets across all 50 US states
  • πŸ—ΊοΈ Interactive Maps: Google Maps integration with geocoding and market locations
  • 🏷️ State-Based Filtering: Filter markets by US state with custom icons
  • πŸ“„ Pagination: Handle large market collections with smooth navigation
  • πŸ“ Detailed Market Info: Hours, addresses, phone numbers, coordinates, and descriptions
  • πŸ” SEO Optimized: Comprehensive meta tags, Open Graph, structured data, and sitemaps
  • πŸ“± Responsive Design: Beautiful UI that works on all devices with optimized images
  • πŸƒβ€β™‚οΈ Fast Performance: Static generation with SvelteKit for optimal speed
  • 🎨 Modern Styling: Tailwind CSS v4 with clean, professional design
  • πŸ“ Blog System: Markdown-based blog with gray-matter frontmatter
  • πŸ†• Dynamic Navigation: Latest blog post displayed with NEW badge in centered navigation
  • πŸ’° Ad System: Configurable custom ads with Google Ads integration

πŸš€ Tech Stack


πŸ“ Project Structure

src/
β”œβ”€β”€ routes/
β”‚   β”œβ”€β”€ [state]/[slug]/       # Dynamic farmer's market pages
β”‚   β”‚   β”œβ”€β”€ +page.svelte      # Market detail page
β”‚   β”‚   └── +page.ts          # Market data loading
β”‚   β”œβ”€β”€ blog/                 # Blog system
β”‚   β”‚   β”œβ”€β”€ +page.svelte      # Blog listing
β”‚   β”‚   β”œβ”€β”€ +page.server.ts   # Blog data loading
β”‚   β”‚   └── [slug]/           # Individual blog posts
β”‚   β”œβ”€β”€ +layout.svelte        # Root layout with navigation
β”‚   └── +page.svelte          # Homepage with state filters
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”œβ”€β”€ ui/               # Reusable UI components
β”‚   β”‚   β”‚   β”œβ”€β”€ ResourceCard.svelte
β”‚   β”‚   β”‚   β”œβ”€β”€ ResourceMap.svelte
β”‚   β”‚   β”‚   β”œβ”€β”€ Pagination.svelte
β”‚   β”‚   β”‚   β”œβ”€β”€ Ad.svelte
β”‚   β”‚   β”‚   └── SEO.svelte
β”‚   β”‚   β”œβ”€β”€ layout/           # Layout components
β”‚   β”‚   β”‚   β”œβ”€β”€ FilterBar.svelte
β”‚   β”‚   β”‚   β”œβ”€β”€ Hero.svelte
β”‚   β”‚   β”‚   β”œβ”€β”€ Navigation.svelte
β”‚   β”‚   β”‚   └── Footer.svelte
β”‚   β”‚   └── blog/             # Blog components
β”‚   β”‚       └── BlogCard.svelte
β”‚   β”œβ”€β”€ data/
β”‚   β”‚   └── resources.json    # Farmer's market data (1000+ markets)
β”‚   β”œβ”€β”€ content/
β”‚   β”‚   └── blog/             # Markdown blog posts
β”‚   β”œβ”€β”€ utils/
β”‚   β”‚   β”œβ”€β”€ slugify.ts        # URL slugification
β”‚   β”‚   β”œβ”€β”€ geocoding.ts      # Google Maps utilities
β”‚   β”‚   β”œβ”€β”€ markdown.ts       # Markdown processing
β”‚   β”‚   └── ads.ts            # Ad system utilities
β”‚   β”œβ”€β”€ services/
β”‚   β”‚   └── blog.ts           # Blog service functions
β”‚   └── config.ts             # Site configuration

βš™οΈ Configuration

Site Configuration

Update the main site settings in src/lib/config.ts:

export const config = {
	siteName: 'FarmerMarket.us',
	siteDescription: `Your complete directory of farmer's markets across America. Find fresh, local produce and artisanal goods in your area with market hours, locations, and vendor information.`,
	defaultSiteUrl: 'https://farmermarket.us/',
	contactEmail: 'hqdirectory@gmail.com',
	// Ad placement configuration
	ads: {
		enabled: true,
		placementRow: 1, // Insert ad after this row
		itemsPerRow: 4, // Grid columns
		showOnResourcePages: true
		// ... ad configuration
	}
};

Environment Variables

Create a .env file in your project root for environment-specific configuration:

# Production domain (used for SEO meta tags)
PUBLIC_SITE_URL=https://yourdomain.com

Environment Examples

Development:

PUBLIC_SITE_URL=http://localhost:5173

Staging:

PUBLIC_SITE_URL=https://staging.yourdomain.com

Production:

PUBLIC_SITE_URL=https://yourdomain.com

Note: The PUBLIC_ prefix makes the variable available to client-side code in SvelteKit.

Deployment Configuration

Vercel

Add environment variables in your Vercel dashboard:

  • Key: PUBLIC_SITE_URL
  • Value: https://yourdomain.com

Netlify

Add to your Netlify environment variables:

PUBLIC_SITE_URL=https://yourdomain.com

Custom Server

Export the environment variable:

export PUBLIC_SITE_URL=https://yourdomain.com
npm run build

πŸ› οΈ Getting Started

Installation

# Clone the repository
git clone <your-repo-url>
cd farmermarket.us

# Install dependencies
npm install

Development

# Start development server
npm run dev

# Open in browser automatically
npm run dev -- --open

Production Build

# Build for production
npm run build

# Preview production build locally
npm run preview

πŸ“ Content Management

Adding Farmer's Markets

Edit src/lib/data/resources.json to add new farmer's markets:

{
	"id": "unique-id",
	"title": "Market Name",
	"description": "Brief description of the farmer's market",
	"longDescription": "<p>Detailed HTML description</p>",
	"image": "/images/resources/state/market-image.avif",
	"phone": "+1 555-123-4567",
	"hours": {
		"monday": "8:00 AM - 2:00 PM",
		"tuesday": "",
		"wednesday": "8:00 AM - 2:00 PM",
		"thursday": "",
		"friday": "8:00 AM - 2:00 PM",
		"saturday": "7:00 AM - 3:00 PM",
		"sunday": ""
	},
	"externalUrl": "https://market-website.com",
	"sponsored": false,
	"address": {
		"street": "123 Market Street",
		"city": "City Name",
		"state": "State Name",
		"zip": "12345"
	},
	"coordinates": {
		"lat": 40.7128,
		"lng": -74.006
	}
}

State Filters

State filters are automatically generated from the market data. Each state has a custom icon defined in src/routes/+page.svelte:

const filters = [
	{ label: 'Alabama', icon: Rocket, state: 'Alabama' },
	{ label: 'Alaska', icon: Snowflake, state: 'Alaska' }
	// ... all 50 states with custom icons
];

Blog Content

Add new blog posts as Markdown files in src/lib/content/blog/:

---
title: 'Your Blog Post Title'
description: 'Brief description for SEO'
date: '2024-01-15'
author: 'Author Name'
---

# Your Blog Post

Content goes here in Markdown format.

Pagination

Markets are automatically paginated when there are more than 20 items. You can adjust this in src/routes/+page.svelte:

const itemsPerPage = 20; // Change this value

πŸ’° Ad System

The project includes a flexible ad system that supports multiple custom ads with randomization and future Google Ads integration.

Features

  • 🎲 Randomized Ads: Each page load displays a random ad from your pool
  • πŸ“ Smart Placement: Configure which grid row ads appear in on directory pages
  • πŸ“„ Resource Page Ads: Display ads on individual resource pages
  • 🎯 Multiple Ad Support: Manage multiple custom ads easily
  • πŸš€ Google Ads Ready: Built-in support for future Google Ads integration
  • βš™οΈ Fully Configurable: Control placement, frequency, and display logic

Configuration

Configure ads in src/lib/config.ts:

export const config = {
	// ... other config
	ads: {
		enabled: true, // Enable/disable ad system
		// Directory page ads
		placementRow: 1, // Insert ad after this row (1-based)
		itemsPerRow: 4, // Must match your grid columns
		// Individual resource page ads
		showOnResourcePages: true, // Enable/disable ads on resource pages

		// Custom ads pool - randomly selected
		customAds: [
			{
				id: 'soc-compliance',
				image: '/ads/soc.png',
				url: 'https://randy.digital'
			}
			// Add more ads here...
		],

		// Google Ads configuration (for future use)
		googleAds: {
			enabled: false, // Will enable when Google Ads are ready
			adSlotId: '', // Your Google Ads slot ID
			frequency: 0.3 // 30% chance to show Google Ad vs custom ad
		}
	}
};

Ad Placement Logic

The system uses a smart placement algorithm:

  • Row-Based: Ads appear after complete rows of resources
  • Example: With placementRow: 1 and itemsPerRow: 4, the ad appears after the 4th resource
  • Responsive: Automatically adapts to your grid configuration
// Placement Examples:
placementRow: 1, itemsPerRow: 4  // Ad after 4 resources (1st row)
placementRow: 2, itemsPerRow: 4  // Ad after 8 resources (2nd row)
placementRow: 3, itemsPerRow: 4  // Ad after 12 resources (3rd row)

The system will automatically calculate the correct insertion point based on your grid layout.

Resource Page Ads

Ads also appear on individual resource pages after the main content. This provides additional ad impressions and monetization opportunities.

Features:

  • Same Ad Pool: Uses the same randomized ad system as directory pages
  • Optimal Placement: Positioned after resource description, before page end
  • Configurable: Can be disabled independently from directory ads
  • Responsive: Adapts to the resource page layout

Configuration:

ads: {
	showOnResourcePages: true,  // Enable ads on individual resource pages
	// ... other settings
}

To disable resource page ads only:

ads: {
	enabled: true,              // Keep directory ads enabled
	showOnResourcePages: false, // Disable resource page ads
	// ... other settings
}

Ad System Components

  • Ad.svelte: Displays custom ads with your branding
  • GoogleAd.svelte: Ready for Google Ads integration (currently placeholder)
  • ads.ts: Utility functions for ad logic and randomization

Disabling Ads

To disable the ad system completely:

ads: {
	enabled: false,
	// ... rest of config
}

Adding New Ads

Simply add new ad objects to the customAds array:

{
	id: 'unique-ad-id',                    // Unique identifier
	image: '/ads/your-ad-image.png',       // Full ad image path
	url: 'https://example.com/landing'     // Click-through URL
}

Ad Image Guidelines

  • Full-Image Design: Ads are complete images that fill the entire ad space
  • Self-Contained: All text, branding, and call-to-action should be part of the image
  • Recommended Size: 1200x400px (3:1 aspect ratio) for banner-style ads
  • Format: PNG, JPG, or WebP
  • File Size: Under 500KB for optimal loading
  • Content: Design the complete ad within the image file
  • Responsive: Images automatically scale to fit the container width

Randomization System

  • Load-Time Selection: A random ad is chosen when the page loads
  • Equal Distribution: All ads have equal chance of being displayed
  • Future Enhancement: Google Ads can be mixed in based on frequency setting

Google Ads Integration (Future)

When ready to integrate Google Ads:

  1. Enable Google Ads:

    googleAds: {
      enabled: true,
      adSlotId: 'your-google-ads-slot-id',
      frequency: 0.3  // 30% Google Ads, 70% custom ads
    }
  2. Update GoogleAd Component: Uncomment the Google Ads code in src/lib/components/ui/GoogleAd.svelte

  3. Add Google Ads Script: The system will automatically handle the integration

Testing Different Placements

You can easily test different ad placements by adjusting the configuration:

// Test ad after first row
placementRow: 1;

// Test ad after second row
placementRow: 2;

// Test ad after third row
placementRow: 3;

The system will automatically calculate the correct insertion point based on your grid layout.

About

Find fresh, local produce and artisanal goods in your area with market hours, locations, and vendor information.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages