Skip to content

Latest commit

Β 

History

History
307 lines (239 loc) Β· 9.2 KB

File metadata and controls

307 lines (239 loc) Β· 9.2 KB

Integration Guide: ExoQuery Site + Examples Web

This guide shows how to integrate the external examples repository with the main ExoQuery website.

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    ExoQuery Website                          β”‚
β”‚                                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚  Built-in        β”‚         β”‚  External Examples   β”‚     β”‚
β”‚  β”‚  Examples        β”‚         β”‚  (Dynamic Loading)   β”‚     β”‚
β”‚  β”‚  (examples.md)   β”‚         β”‚                      β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚         β”‚                              β”‚                    β”‚
β”‚         β”‚                              β”‚                    β”‚
β”‚         β–Ό                              β–Ό                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚  β”‚         Example Display Component                 β”‚      β”‚
β”‚  β”‚  β€’ Checks if slug exists in built-in examples    β”‚      β”‚
β”‚  β”‚  β€’ Falls back to loading from external repo      β”‚      β”‚
β”‚  β”‚  β€’ Caches external examples in localStorage      β”‚      β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β”‚
                               β”‚ Fetches from
                               β–Ό
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚   External Examples Repository           β”‚
        β”‚                                          β”‚
        β”‚   GitHub Pages / jsDelivr CDN           β”‚
        β”‚   β€’ manifest.json                       β”‚
        β”‚   β€’ examples/*.json                     β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“¦ Setup

1. Install External Examples Utilities

The utility file has been created at:

exoquery-site/src/utils/loadExternalExamples.ts

2. Update HeroSection Component

Modify src/components/HeroSection.astro to support dynamic loading:

---
import CodePlayground from './CodePlayground.vue';
import HeroCodeLoader from './HeroCodeLoader.vue';

// Default example (fallback)
const defaultHeroCode = `...`;
---

<section class="hero" id="home">
  <div class="hero-content">
    <h1>Stop Writing 300 Queries<br/>When You Need 30</h1>
    <p class="subtitle">The only Kotlin library with true query composition.</p>
    
    <!-- Use new loader component that handles ?example= query param -->
    <HeroCodeLoader 
      client:only="vue" 
      :defaultCode="defaultHeroCode"
      :defaultSqlOutput="heroSqlOutput"
      :defaultSchema="heroCodeSchema"
    />
  </div>
</section>

3. Create HeroCodeLoader Component

Create src/components/HeroCodeLoader.vue:

<template>
  <CodePlayground 
    :code="currentCode" 
    :initial-sql-code="currentSqlOutput" 
    :schema="currentSchema"
  />
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import CodePlayground from './CodePlayground.vue';
import { loadExternalExample } from '../utils/loadExternalExamples';

interface Props {
  defaultCode: string;
  defaultSqlOutput: string;
  defaultSchema: string;
}

const props = defineProps<Props>();

const currentCode = ref(props.defaultCode);
const currentSqlOutput = ref(props.defaultSqlOutput);
const currentSchema = ref(props.defaultSchema);

async function loadExampleFromUrl() {
  if (typeof window === 'undefined') return;
  
  const params = new URLSearchParams(window.location.search);
  const exampleSlug = params.get('example');
  
  if (!exampleSlug) return;
  
  console.log(`Loading external example: ${exampleSlug}`);
  
  const example = await loadExternalExample(exampleSlug);
  
  if (example) {
    currentCode.value = example.code;
    currentSqlOutput.value = example.output;
    currentSchema.value = example.schema || '';
    console.log(`Loaded external example: ${example.title}`);
  } else {
    console.warn(`Failed to load external example: ${exampleSlug}`);
  }
}

onMounted(() => {
  loadExampleFromUrl();
  
  // Listen for URL changes
  window.addEventListener('popstate', loadExampleFromUrl);
});
</script>

4. Update Examples Component (Optional)

To show external examples in the examples browser, update Examples.vue:

import { ref, onMounted, computed } from 'vue';
import examplesContent from '../content/examples.md?raw';
import { parseExamples, type Example } from '../utils/parseExamples';
import { getAllExternalExamples } from '../utils/loadExternalExamples';

// Parse built-in examples
const builtInExamples: Example[] = parseExamples(examplesContent);
const externalExamples = ref<Example[]>([]);

// Combine both
const examples = computed(() => [...builtInExamples, ...externalExamples.value]);

onMounted(async () => {
  // Load external examples metadata
  const external = await getAllExternalExamples();
  if (external) {
    // Convert manifest entries to Example format
    externalExamples.value = Object.entries(external).map(([slug, meta]) => ({
      slug,
      title: meta.title,
      description: meta.description,
      category: meta.category,
      icon: meta.icon,
      code: '', // Will be loaded on demand
      output: '',
    }));
  }
});

πŸ”§ Local Development

Quick Setup

Run the setup script:

cd exoquery-examples-web
./setup-local-dev.sh

This will:

  1. Build the examples
  2. Create a symlink in exoquery-site/public/examples-local
  3. Create .env.development if needed

Manual Setup

  1. Build examples:
cd exoquery-examples-web
npm run build
  1. Create symlink:
cd exoquery-site/public
ln -s ../../exoquery-examples-web/dist examples-local
  1. The site will now use local examples in dev mode

Testing

Start the site:

cd exoquery-site
npm run dev

Test URLs:

  • Built-in example: http://localhost:4321/examples/basic-select
  • External example: http://localhost:4321/#home?example=window-functions

πŸš€ Production Deployment

Update Configuration

In src/utils/loadExternalExamples.ts, update the GitHub username:

const EXTERNAL_EXAMPLES_CONFIG = {
  baseUrl: import.meta.env.DEV
    ? '/examples-local'
    : 'https://cdn.jsdelivr.net/gh/YOUR_USERNAME/exoquery-examples-web@main/dist',
  // ...
};

Enable GitHub Pages

In the exoquery-examples-web repository:

  1. Go to Settings β†’ Pages
  2. Source: "GitHub Actions"
  3. Push to main to trigger deployment

Verify

After ~2 minutes:

  • Check manifest: https://YOUR_USERNAME.github.io/exoquery-examples-web/manifest.json
  • Check example: https://YOUR_USERNAME.github.io/exoquery-examples-web/examples/window-functions.json

πŸ“Š URL Patterns

Built-in Examples

https://exoquery.io/examples/basic-select
https://exoquery.io/examples/complex-joins

External Examples (Hero Section)

https://exoquery.io/#home?example=window-functions
https://exoquery.io/#home?example=advanced-subqueries

Sharing Examples

Users can share direct links:

https://exoquery.io/#home?example=recursive-cte

πŸ” Troubleshooting

Examples not loading locally

  • Check symlink exists: ls -la exoquery-site/public/examples-local
  • Rebuild examples: cd exoquery-examples-web && npm run build
  • Clear cache: Open DevTools β†’ Application β†’ Local Storage β†’ Clear

404 in production

  • Verify GitHub Pages is enabled
  • Check GitHub Actions completed successfully
  • Wait 2-5 minutes for CDN propagation
  • Try force refresh: Add ?v=timestamp to URL

CORS errors

  • GitHub Pages: βœ… CORS enabled by default
  • jsDelivr: βœ… CORS enabled by default
  • Custom domain: May need CORS headers

🎯 Benefits

For Users

  • βœ… More examples without site updates
  • βœ… Shareable direct links
  • βœ… Fast loading (CDN + caching)

For Developers

  • βœ… Add examples without site rebuild
  • βœ… Rapid local iteration
  • βœ… Version controlled examples
  • βœ… TypeScript type safety

For Maintenance

  • βœ… Separate concerns (site vs content)
  • βœ… Independent deployment
  • βœ… Easy rollback (Git tags)

πŸ“š API Reference

See src/utils/loadExternalExamples.ts for:

  • loadExternalExample(slug) - Load single example
  • loadExternalManifest() - Get all available examples
  • isExternalExample(slug) - Check if example exists
  • clearExternalCache() - Clear localStorage cache