Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 4 additions & 26 deletions bin/dev-router.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,6 @@
use Cake\Http\ServerRequestFactory;
use Glaze\Application;
use Glaze\Config\ProjectConfigurationReader;
use Glaze\Http\DevPageRequestHandler;
use Glaze\Http\Middleware\ContentAssetMiddleware;
use Glaze\Http\Middleware\ErrorHandlingMiddleware;
use Glaze\Http\Middleware\PublicAssetMiddleware;
use Glaze\Http\Middleware\StaticAssetMiddleware;
use Glaze\Http\StaticPageRequestHandler;

require dirname(__DIR__) . '/vendor/autoload.php';

Expand All @@ -30,31 +24,19 @@

$includeDrafts = getenv('GLAZE_INCLUDE_DRAFTS') === '1';
$staticMode = getenv('GLAZE_STATIC_MODE') === '1';
$debug = getenv('GLAZE_DEBUG') === '1';

$application = new Application();
$application->bootstrap();
$container = $application->getContainer();

(new ProjectConfigurationReader())->read($projectRoot);
Configure::write('projectRoot', $projectRoot);
Configure::write('debug', $debug);
if ($includeDrafts) {
Configure::write('build.drafts', true);
}

/** @var \Glaze\Http\Middleware\PublicAssetMiddleware $publicAssetMiddleware */
$publicAssetMiddleware = $container->get(PublicAssetMiddleware::class);
/** @var \Glaze\Http\Middleware\StaticAssetMiddleware $staticAssetMiddleware */
$staticAssetMiddleware = $container->get(StaticAssetMiddleware::class);
/** @var \Glaze\Http\Middleware\ContentAssetMiddleware $contentAssetMiddleware */
$contentAssetMiddleware = $container->get(ContentAssetMiddleware::class);

if ($staticMode) {
/** @var \Glaze\Http\StaticPageRequestHandler $fallbackHandler */
$fallbackHandler = $container->get(StaticPageRequestHandler::class);
} else {
/** @var \Glaze\Http\DevPageRequestHandler $fallbackHandler */
$fallbackHandler = $container->get(DevPageRequestHandler::class);
}
$fallbackHandler = $application->fallbackHandler($staticMode);

$requestMethod = $_SERVER['REQUEST_METHOD'] ?? null;
if (!is_string($requestMethod) || $requestMethod === '') {
Expand All @@ -76,11 +58,7 @@
$request = $request->withQueryParams($queryParams);
}

$queue = new MiddlewareQueue();
$queue->add(new ErrorHandlingMiddleware(true));
$queue->add($publicAssetMiddleware);
$queue->add($staticAssetMiddleware);
$queue->add($contentAssetMiddleware);
$queue = $application->middleware(new MiddlewareQueue(), $staticMode);

$response = (new Runner())->run($queue, $request, $fallbackHandler);

Expand Down
1 change: 1 addition & 0 deletions docs/content/reference/commands.dj
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ Options:
- `--static` serve prebuilt `public/`
- `--build` prebuild before static serve (`--static` required)
- `--drafts` include drafts for static mode
- `--debug` enable debug mode
- `--vite` enable Vite integration in live mode
- `--vite-host <host>` Vite host (default `127.0.0.1`)
- `--vite-port <port>` Vite port (default `5173`)
Expand Down
30 changes: 16 additions & 14 deletions docs/content/reference/recipes.dj
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ weight: 50

Short, copy-paste patterns for common real-world needs.

## Environment-aware templates with `$debug`
## Environment-aware templates with `$this->isLiveMode()`

Every template receives a `$debug` boolean that is `true` when Glaze is running in
`glaze serve` (development) mode and `false` during `glaze build` (production).
Inside templates, `$this` is a `SiteContext` object. Use `$this->isLiveMode()` to
detect whether Glaze is running in `glaze serve` (live mode) or `glaze build`
(static build mode).

This lets you keep a single template codebase while varying content by environment —
no separate config files required.

::: info
`$debug` maps 1-to-1 with the `glaze serve` / `glaze build` distinction
`$this->isLiveMode()` maps 1-to-1 with the `glaze serve` / `glaze build` distinction
— it is not affected by your NEON config, OS environment variables, or Vite settings.
:::

Expand All @@ -26,7 +27,7 @@ Keep your development credentials out of production builds (and vice versa):

```php
<?php
$apiKey = $debug
$apiKey = $this->isLiveMode()
? 'pk_test_xxxxxxxxxxxxxxxx' // development key
: 'pk_live_xxxxxxxxxxxxxxxx'; // production key
?>
Expand All @@ -48,7 +49,7 @@ site:

```php
<?php
$apiKey = $debug
$apiKey = $this->isLiveMode()
? $site->siteMeta('apiKeyDev')
: $site->siteMeta('apiKeyLive');
?>
Expand All @@ -63,7 +64,7 @@ Emit the GTM snippet only when generating the static build so analytics data is
never polluted by local development traffic:

```php
<?php if (!$debug): ?>
<?php if (!$this->isLiveMode()): ?>
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
Expand All @@ -77,7 +78,7 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
And the corresponding `<noscript>` body tag:

```php
<?php if (!$debug): ?>
<?php if (!$this->isLiveMode()): ?>
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
Expand All @@ -88,7 +89,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
The same pattern works for Google Analytics 4 directly:

```php
<?php if (!$debug): ?>
<?php if (!$this->isLiveMode()): ?>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
Expand All @@ -105,7 +106,7 @@ Render a strip at the top of every page in dev mode so it is immediately clear y
are not looking at the live site:

```php
<?php if ($debug): ?>
<?php if ($this->isLiveMode()): ?>
<div class="alert alert-warning rounded-none text-sm text-center">
Development preview — not the live site
</div>
Expand All @@ -114,13 +115,14 @@ are not looking at the live site:

### Combine multiple conditions

You can mix `$debug` with other template variables freely:
You can mix `$this->isLiveMode()` with other template variables freely:

```php
<?php
$gaId = $debug ? null : 'G-XXXXXXXX';
$cookieBanner = !$debug;
$chatWidget = !$debug && $site->siteMeta('chat.enabled');
$isLiveMode = $this->isLiveMode();
$gaId = $isLiveMode ? null : 'G-XXXXXXXX';
$cookieBanner = !$isLiveMode;
$chatWidget = !$isLiveMode && $site->siteMeta('chat.enabled');
?>
```

Expand Down
4 changes: 3 additions & 1 deletion docs/content/templating/index.dj
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ These variables are injected into every page template by Glaze:
| `$page` | `ContentPage` | Full page object |
| `$meta` | `array` | Merged page metadata |
| `$site` | `SiteConfig` | Global site config |
| `$debug` | `bool` | `true` when running `glaze serve`, `false` during `glaze build` |

Use `$this->isLiveMode()` from `SiteContext` to check live (`glaze serve`) vs build (`glaze build`) mode.

### `$page` properties

Expand Down Expand Up @@ -137,6 +138,7 @@ $this->tree() // root Section node
$this->section('blog') // ?Section for a path (supports nesting: docs/guides)
$this->sections() // array<string, Section> — top-level sections, ordered by weight
$this->rootPages() // PageCollection — root-level pages (no section)
$this->isLiveMode() // bool -- true in live mode (`glaze serve`), false in build mode
$this->isCurrent('/blog/') // bool -- true when current page matches path
$this->previous(?callable $predicate = null) // ?ContentPage — previous in global display order
$this->next(?callable $predicate = null) // ?ContentPage — next in global display order
Expand Down
1 change: 1 addition & 0 deletions resources/backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
196 changes: 196 additions & 0 deletions resources/backend/assets/css/dev.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}

:root {
--glaze-bg: #0f1117;
--glaze-surface: #1a1d27;
--glaze-border: #2d3148;
--glaze-text: #e2e8f0;
--glaze-muted: #64748b;
--glaze-accent: #6366f1;
--glaze-warn: #f59e0b;
--glaze-info: #38bdf8;
--glaze-radius: 6px;
--glaze-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

body {
font-family: var(--glaze-font);
background: var(--glaze-bg);
color: var(--glaze-text);
font-size: 14px;
line-height: 1.6;
min-height: 100vh;
}

.glaze-container {
max-width: 1100px;
margin: 0 auto;
padding: 0 24px;
}

/* Header */
.glaze-header {
border-bottom: 1px solid var(--glaze-border);
padding: 12px 0;
margin-bottom: 32px;
}

.glaze-header-inner {
display: flex;
align-items: center;
gap: 24px;
}

.glaze-logo {
font-size: 16px;
font-weight: 700;
color: var(--glaze-accent);
letter-spacing: -0.01em;
}

.glaze-nav {
display: flex;
gap: 4px;
}

.glaze-nav-link {
padding: 4px 12px;
border-radius: var(--glaze-radius);
color: var(--glaze-muted);
text-decoration: none;
font-size: 13px;
transition: color 0.15s, background 0.15s;
}

.glaze-nav-link:hover {
color: var(--glaze-text);
background: var(--glaze-surface);
}

.glaze-nav-active {
color: var(--glaze-text);
background: var(--glaze-surface);
}

/* Page header */
.glaze-main {
padding-bottom: 48px;
}

.glaze-page-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 20px;
}

.glaze-page-title {
font-size: 20px;
font-weight: 600;
}

/* Badge */
.glaze-badge {
background: var(--glaze-surface);
border: 1px solid var(--glaze-border);
color: var(--glaze-muted);
padding: 2px 8px;
border-radius: 999px;
font-size: 12px;
}

/* Table */
.glaze-table-wrap {
overflow-x: auto;
border: 1px solid var(--glaze-border);
border-radius: var(--glaze-radius);
}

.glaze-table {
width: 100%;
border-collapse: collapse;
}

.glaze-table thead tr {
background: var(--glaze-surface);
}

.glaze-table th {
padding: 10px 16px;
text-align: left;
font-weight: 500;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--glaze-muted);
border-bottom: 1px solid var(--glaze-border);
}

.glaze-table td {
padding: 10px 16px;
border-bottom: 1px solid var(--glaze-border);
vertical-align: middle;
}

.glaze-table tbody tr:last-child td {
border-bottom: none;
}

.glaze-table tbody tr:hover td {
background: var(--glaze-surface);
}

/* Link */
.glaze-link {
color: var(--glaze-accent);
text-decoration: none;
font-family: 'SFMono-Regular', Consolas, monospace;
font-size: 13px;
}

.glaze-link:hover {
text-decoration: underline;
}

/* Tags */
.glaze-tag {
display: inline-block;
padding: 2px 8px;
border-radius: 4px;
font-size: 11px;
font-weight: 500;
background: var(--glaze-surface);
border: 1px solid var(--glaze-border);
color: var(--glaze-muted);
}

.glaze-tag-warn {
border-color: var(--glaze-warn);
color: var(--glaze-warn);
}

.glaze-tag-info {
border-color: var(--glaze-info);
color: var(--glaze-info);
}

.glaze-muted {
color: var(--glaze-muted);
}

.glaze-flags {
display: flex;
gap: 4px;
flex-wrap: wrap;
}

/* Empty state */
.glaze-empty {
color: var(--glaze-muted);
text-align: center;
padding: 48px;
}
7 changes: 7 additions & 0 deletions resources/backend/assets/dist/.vite/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"assets/css/dev.css": {
"file": "assets/dev-BBpMC4gS.css",
"src": "assets/css/dev.css",
"isEntry": true
}
}
1 change: 1 addition & 0 deletions resources/backend/assets/dist/assets/dev-BBpMC4gS.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading