# Preloop Console
This directory contains the new Preloop frontend, a modern web application built with Lit, Vite, and TypeScript. It uses Shoelace Web Components for UI.
## Description
This frontend is a single-page application (SPA) that provides a rich, interactive user experience for managing MCP servers, issue trackers, and more through the Preloop API. It is designed to be fast, responsive, and maintainable.
## Development
### Prerequisites
- Node.js (v18 or higher)
- npm (v9 or higher)
### Installing Dependencies
To install the necessary dependencies, run the following command:
```bash
npm install
```
### Running the Development Server
To start the local development server with Hot Module Replacement (HMR), run:
```bash
npm run dev
```
The application will be available at `http://localhost:5173` by default.
### Building for Production
To create an optimized production build, run:
```bash
npm run build
```
The output files will be placed in the `dist/` directory.
### Running Tests
To run the test suite using Web Test Runner, use the following command:
```bash
npm run test
```
## Architecture
### SSR Content Slotting for SEO
The frontend uses a slotting mechanism to provide SEO-friendly server-side rendered content while maintaining the benefits of a single-page application (SPA).
#### How It Works
1. **Build Time (`vite-plugin-brand.ts`)**:
- The Vite plugin generates static HTML pages (index.html, about.html, pricing.html, etc.)
- Each page includes pre-rendered content inside web component tags in the light DOM
- Content is wrapped in appropriate wrapper components:
- Landing page: `<landing-view>` with slotted content
- Static pages: `<static-view-wrapper>` with article content
- A `data-ssr-route` attribute on `<lit-app>` indicates which route the SSR content is for
2. **Runtime Hydration (`lit-app.ts`)**:
- On page load, `firstUpdated()` checks if SSR content exists in the light DOM
- If the SSR route matches the current URL path, the content is moved to the router outlet
- The router then reuses this existing content instead of creating new components
- If routes don't match (e.g., SPA navigation), SSR content is removed
3. **Component Consumption**:
- `landing-view` reads slotted content via named slots (e.g., `slot="hero-title"`)
- `static-view-wrapper` uses a default slot to display article content
- Components can also load content dynamically via JSON/markdown for client-side navigation
#### File Structure
```
vite-plugin-brand.ts # Generates SSR HTML at build time
src/components/
lit-app.ts # Handles SSR content hydration
static-view-wrapper.ts # Wrapper for static pages (privacy, about, etc.)
static-view.ts # Dynamic markdown loader for client-side nav
src/views/public/
landing-view.ts # Landing page with slot consumption
```
#### Key Functions
- `generateSlottedContentForRoute()` - Creates slotted HTML for landing page
- `generateFullHtmlPage()` - Generates complete HTML pages for static routes
- `loadMarkdownContent()` - Converts markdown to styled HTML articles
#### Benefits
- **SEO**: Search engines see fully rendered content on first load
- **Performance**: No flash of unstyled content (FOUC) with critical CSS
- **SPA Experience**: After hydration, navigation is instant client-side
- **Maintainability**: Content defined in `brands.yaml` and markdown files