# Framex Engine Documentation

Framex is a small PHP engine for building fast websites with plain PHP views, Markdown pages, reusable templates, and Tailwind CSS 4. It is designed to stay simple: URLs map to files, templates wrap views, and assets live in `public`.

## Project Structure

The important folders are:

```text
app/views/              Page views for URLs
core/                   Router, renderer, helpers, and configuration
templates/              Layout templates and partials
templates/partials/     Shared pieces such as top menu and footer
public/                 Web root for CSS, JS, images, and index.php
public/css/src/         Tailwind source CSS
public/css/style.css    Compiled production CSS
public/js/init.js       Theme toggle and menu behavior
```

The web server should point to `public` as the document root.

## URL Routing

Framex resolves the browser URL to a file inside `app/views`.

For a request like:

```text
/about
```

Framex checks these files in order:

```text
app/views/about.php
app/views/about/index.php
app/views/about.md
app/views/about/index.md
```

The first file that exists is rendered. If none exists, Framex falls back to `templates/error404.php`.

Examples:

```text
/                 -> app/views/index.php
/docs             -> app/views/docs/index.md
/about            -> app/views/about/index.md
/pricing          -> app/views/pricing.php
/blog/hello       -> app/views/blog/hello.php or app/views/blog/hello/index.md
```

Trailing slashes are normalized, so `/docs/` and `/docs` resolve the same way.

## PHP Views

Use PHP views when a page needs custom markup, variables, conditionals, loops, forms, or reusable PHP logic.

Create a file:

```text
app/views/pricing.php
```

Then visit:

```text
/pricing
```

A PHP view can set page metadata by assigning values to the `$data` array:

```php
<?php
$data['title'] = 'Pricing - Framex';
$data['metaDescription'] = 'Simple pricing page built with Framex.';
$data['bodyClass'] = 'bg-slate-50 text-slate-950 dark:bg-slate-950 dark:text-slate-100';
?>

<main class="section">
  <div class="contain">
    <h1 class="text-4xl font-semibold">Pricing</h1>
    <p class="mt-4 text-slate-600 dark:text-slate-400">Choose the right plan.</p>
  </div>
</main>
```

The rendered PHP view is injected into the main template through `<?= $view ?>`.

## Markdown Views

Use Markdown views for documentation, simple content pages, articles, and static text-heavy pages.

Create a file:

```text
app/views/guide/index.md
```

Then visit:

```text
/guide
```

Markdown files are parsed by `Parsedown` and automatically wrapped in:

```html
<article class="prose prose-shell">
  ...
</article>
```

That means Markdown pages automatically get readable typography, spacing, links, lists, code blocks, tables, blockquotes, images, and light/dark colors.

Example Markdown page:

```md
# My Guide

This page is rendered from Markdown.

## Features

- Clean URLs
- Automatic styling
- Light and dark mode

```php
echo 'Code blocks are styled too';
```
```

## Templates

The default layout is:

```text
templates/main.php
```

It handles:

- HTML document structure
- Meta tags
- CSS include
- Dark-mode bootstrap
- Top menu partial
- Current view output
- Footer partial
- JavaScript include

The main content flow is:

```php
<?= partial('topmenu') ?>
<?= $view ?>
<?= partial('footer') ?>
```

Partials live in:

```text
templates/partials/
```

For example:

```text
templates/partials/topmenu.php
templates/partials/footer.php
```

Load a partial with:

```php
<?= partial('topmenu') ?>
```

## Metadata

PHP views can customize metadata with `$data`.

Common keys:

```php
$data['title'] = 'Page title';
$data['metaDescription'] = 'Page description for search and sharing.';
$data['metaImage'] = image(1200, 630);
$data['bodyClass'] = 'custom body classes';
$data['template'] = 'main';
```

If a key is not set, `templates/main.php` uses sensible defaults.

Markdown views currently use the default metadata unless the renderer is extended to read front matter.

## Assets

Public files are served from `public`.

Examples:

```text
public/css/style.css -> /css/style.css
public/js/init.js    -> /js/init.js
public/images/logo.png -> /images/logo.png
```

Use the `asset()` helper for cache-busted URLs:

```php
<link rel="stylesheet" href="<?= asset('css/style.css') ?>">
<script src="<?= asset('js/init.js', ['prefix' => 'framex', 'hash' => true]) ?>"></script>
```

Useful asset options:

```php
asset('css/style.css');
asset('js/init.js', ['hash' => true]);
asset('images/logo.png', ['absolute' => true]);
asset('images/missing.png', ['fallback' => '/images/default.png']);
```

## Tailwind CSS

Framex uses Tailwind CSS 4 through the Tailwind CLI.

Install dependencies:

```bash
npm install
```

Build CSS:

```bash
npm run build:css
```

Watch CSS during development:

```bash
npm run watch:css
```

Source CSS:

```text
public/css/src/style.css
```

Compiled CSS:

```text
public/css/style.css
```

Tailwind scans these sources:

```css
@source "../../../templates/**/*.php";
@source "../../../app/**/*.php";
@source "../../../app/**/*.md";
```

When you add new Tailwind classes in PHP or Markdown files, rebuild the CSS.

## Reusable CSS Classes

The project includes reusable classes in `public/css/src/style.css`.

Layout:

```html
<section class="section">
  <div class="contain">...</div>
</section>
```

Buttons:

```html
<a class="btn btn-primary" href="/docs">Primary</a>
<a class="btn btn-secondary" href="/about">Secondary</a>
<button class="btn btn-ghost">Ghost</button>
```

Cards:

```html
<article class="card">
  <h2>Card title</h2>
  <p>Card content.</p>
</article>
```

Preset backgrounds:

```html
<div class="bg-pre-blue">Blue preset</div>
<div class="bg-pre-emerald">Emerald preset</div>
<div class="bg-pre-amber">Amber preset</div>
<div class="bg-pre-rose">Rose preset</div>
```

These presets include both light and dark colors.

## Light and Dark Mode

Dark mode is controlled by the `dark` class on the `<html>` element.

The inline script in `templates/main.php` runs before the stylesheet loads. It checks:

1. The saved `framex-theme` value in `localStorage`.
2. The browser system preference.
3. Light mode as the fallback.

The toggle buttons in `templates/partials/topmenu.php` use:

```html
data-theme-toggle
```

The behavior is implemented in:

```text
public/js/init.js
```

Use Tailwind dark variants anywhere:

```html
<div class="bg-white text-slate-950 dark:bg-slate-900 dark:text-white">
  Theme-aware content
</div>
```

## Running Locally

Install dependencies and build CSS:

```bash
npm install
npm run build:css
```

Start PHP's built-in server:

```bash
php -S localhost:8000 -t public
```

Open:

```text
http://localhost:8000/
```

Useful URLs:

```text
/          Landing page
/docs      This documentation
/about     Example Markdown page
```

## Adding a New Page

For a PHP page:

```text
app/views/services.php
```

Visit:

```text
/services
```

For a Markdown page:

```text
app/views/services/index.md
```

Visit:

```text
/services
```

For a nested page:

```text
app/views/blog/hello-world/index.md
```

Visit:

```text
/blog/hello-world
```

## Recommended Workflow

1. Add or edit a PHP or Markdown view in `app/views`.
2. Use `templates/partials` for shared UI.
3. Use `.section`, `.contain`, `.btn`, `.card`, and preset backgrounds for consistent design.
4. Run `npm run build:css` after changing Tailwind classes.
5. Test the URL in the browser.

Framex works best when pages stay close to the filesystem, shared layout stays in templates, and reusable styling stays in the Tailwind source CSS.
