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
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@ This serves two purposes:
### Added
- Added a configuration option to disable the footer scroll-to-top button independently of the footer in https://github.com/hydephp/develop/pull/2459
- Added Blade Blocks for rendering Blade and Blade components from fenced code blocks in Markdown pages. They are controlled by the existing `markdown.enable_blade` option. ([#2504](https://github.com/hydephp/develop/pull/2504))
- Added built-in `terminal` fenced code blocks with command prompt styling and optional Symfony Console formatting using the `terminal xml` info string. ([#2188](https://github.com/hydephp/develop/issues/2188), [#2485](https://github.com/hydephp/develop/issues/2485))
- Added built-in `terminal` fenced code blocks with command prompt styling, an optional window title using the `title="…"` modifier, and optional Symfony Console formatting using the `terminal xml` info string. ([#2188](https://github.com/hydephp/develop/issues/2188), [#2485](https://github.com/hydephp/develop/issues/2485))
- Added support for lazy `InMemoryPage` contents closures. The current page is passed as the first argument whenever the contents are requested.
- Added a `title="…"` modifier to set a code block's filepath label on the fence, as an alternative to the `// filepath:` comment. The language is optional when using it, and the modifier takes precedence if you use both.

### Changed
- Blade in Markdown is now enabled by default. The `markdown.enable_blade` option controls both `[Blade]:` directives and executable Blade Blocks; set it to `false` when compiling untrusted or unreviewed Markdown.
- Raw HTML in Markdown is now enabled by default. Set `markdown.allow_html` to `false` when compiling untrusted or unreviewed Markdown to strip potentially unsafe HTML tags.
- `InMemoryPage` now requires callers to select either `contents` or `view`; configuring both throws an `InvalidArgumentException` instead of silently giving contents precedence.
- `InMemoryPage` now treats an empty string as an omitted `view`, matching the existing compile-time behavior and allowing literal contents to be used with an empty view value.
- Fenced code blocks are now rendered through the publishable `components/markdown/code-block.blade.php` view, which receives the block's finished markup as `$contents`, along with `$language` and `$label`. Syntax highlighting is unchanged, as the view wraps the highlighted code rather than producing it. The generated markup around the code has changed accordingly, with `hyde-code-block` and `hyde-code-block-label` as stable hooks for your own CSS.
- Breaking: Renamed the filepath label view from `components/filepath-label.blade.php` to `components/markdown/code-block-label.blade.php`. A published copy of the old view is no longer used, so port any customizations over to the new one.

### Deprecated
- for changes that will be removed in upcoming releases.
Expand All @@ -36,6 +39,8 @@ This serves two purposes:
- Removed the `InMemoryPage` instance macro API. Use a contents closure for dynamic output, or extend `InMemoryPage` to add custom methods and behavior.

### Fixed
- Filepath labels are now only read from the first line of a fenced code block, as documented. A matching comment anywhere else in the document, including further down a code block, was previously turned into a label too.
- Fixed the closing delimiter of a `/* filepath: … */` or `<!-- filepath: … -->` comment ending up in the rendered label.
- Improved documentation page detection in MarkdownService so it works for child classes in https://github.com/hydephp/develop/pull/2332
- Fixed bug causing build manifest to not generate when a site has dynamic pages in https://github.com/hydephp/develop/pull/2450
- Fixed bug causing errors in the build manifest task not showing in console in https://github.com/hydephp/develop/pull/2451
Expand Down
115 changes: 115 additions & 0 deletions HYDEPHP_V3_PLANNING.md

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,27 @@ new InMemoryPage('example', view: '');
new InMemoryPage('example', view: null);
```

## Port Your Filepath Label View

Fenced code blocks are now rendered through a Blade view, and the filepath label view moved along with them, from
`components/filepath-label.blade.php` to `components/markdown/code-block-label.blade.php`.

If you never published the label view, there is nothing to do here.

If you did publish and customize it, your copy is no longer used, and your site renders with Hyde's default label
until you move your changes over. Publish the new views, choosing them individually so your other published views are
left alone, then re-apply your changes and delete the old file:

```bash
php hyde publish:views
```

>warning Passing the group name, as in `php hyde publish:views components`, publishes the whole group and overwrites every component view you have already customized.

The markup around code blocks has also changed, so compare a few pages against your old site if you have custom CSS
for them. The `hyde-code-block` and `hyde-code-block-label` classes are stable hooks you can target instead of
matching the markup structure. Syntax highlighting is unaffected.

## Review Drafts and Future-Dated Blog Posts

HydePHP v3 keeps two kinds of blog post out of your built site: those marked `draft: true` in front matter, and those whose date is set in the future. Drafts and scheduled posts are skipped during auto-discovery, so they get no route, are not compiled to `_site`, and are left out of post listings, the sitemap, and the RSS feed. The date rule applies to both front matter dates and filename date prefixes.
Expand All @@ -324,6 +345,8 @@ Use this checklist to track your upgrade progress:
- [ ] Moved `InMemoryPage` `compile` macro callbacks into the contents argument and replaced other macros with subclass methods
- [ ] Updated `InMemoryPage` calls to supply only one of `contents` and `view`
- [ ] Checked `_posts` for drafts and blog posts dated in the future, and set up recurring builds if scheduling posts
- [ ] Ported any `filepath-label.blade.php` customizations to `markdown/code-block-label.blade.php`, and deleted the old file
- [ ] Compared pages against your old site if you have custom CSS for code blocks or filepath labels

## Troubleshooting

Expand Down
2 changes: 1 addition & 1 deletion _media/app.css

Large diffs are not rendered by default.

48 changes: 47 additions & 1 deletion docs/digging-deeper/advanced-markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ Note that these currently do not support multi-line blockquotes.
## Code Block Filepaths

When browsing these documentation pages you may have noticed a label in the top right corner of code blocks specifying the file path.
These are also created by using a custom Hyde feature that turns code comments into automatic code blocks.
These are also created by using a custom Hyde feature that turns code comments into automatic labels.
If you would rather keep the label out of the code, you can set it on the code fence instead.

### Usage

Expand Down Expand Up @@ -291,6 +292,37 @@ console.log('Hello World!');

If you have a newline after the filepath, like in the first example, it will be removed so your code stays readable.

### Title modifier

You can also set the label with a `title` modifier on the code fence, using the same syntax as
[terminal code blocks](#window-titles). This is handy when you would rather not add a comment to the code itself.

````markdown
```php title="hello-world.php"
echo 'Hello World!';
```
````

Which becomes:

```php title="hello-world.php"
echo 'Hello World!';
```

The quoting rules are the same as for terminal titles. Double quotes are canonical, single quotes are also accepted,
and malformed values are reported as errors instead of being guessed at.

The language is optional here, so you can label a block without one:

````markdown
``` title=".env"
APP_NAME=HydePHP
```
````

If you use both syntaxes on the same block, the modifier takes precedence. Either way, the comment is removed from
the code.

### Advanced usage

Since HTML in Markdown is enabled by default, anything within the path label will be rendered as HTML. This means you
Expand All @@ -307,6 +339,20 @@ can add links, or even images to the label. This requires `allow_html` to remain

The filepaths are hidden on mobile devices using CSS to prevent them from overlapping with the code block.

### Customizations

The code block markup provides stable styling hooks for customization. Use `hyde-code-block` to style the block, and
`hyde-code-block-label` to style the filepath label.

You can customize the markup itself by publishing Hyde's Blade components:

```bash
php hyde publish:views
```

The code block component will be published to `resources/views/vendor/hyde/components/markdown/code-block.blade.php`,
and the label component it renders to `markdown/code-block-label.blade.php`.


## Heading Permalinks

Expand Down
123 changes: 71 additions & 52 deletions docs/digging-deeper/composable-markdown-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,14 @@ loops, `@include`, config calls, and the full Tailwind class set inside them.

| Block | Syntax | View | Mechanism |
|-----------------------------------------|-------------------------------|------------------------------------|----------------------|
| [Code blocks](#code-blocks) | ` ```php ` | `markdown/code-block.blade.php` | CommonMark renderer |
| [Terminal blocks](#terminal-blocks) | ` ```terminal ` | `markdown/terminal.blade.php` | CommonMark renderer |
| [Coloured blockquotes](#coloured-blockquotes) | `>info Text` | `colored-blockquote.blade.php` | Markdown pre-processor |
| [Headings](#headings) | `## Heading` | `markdown-heading.blade.php` | CommonMark renderer |
| [Filepath labels](#code-block-filepath-labels) | `// filepath: foo.php` | `filepath-label.blade.php` | Markdown post-processor |
| [Blade component blocks](#blade-component-blocks) | ` ```blade component="x" ` | *any component you write* | Markdown pre-processor |

Code blocks hand their filepath label off to a [second view](#view-contract), which can be published on its own.

All view paths are relative to `resources/views/components/` in the framework package, and to
`resources/views/vendor/hyde/components/` once published into your project.

Expand All @@ -78,9 +80,10 @@ Published views land in `resources/views/vendor/hyde/components/`, mirroring the
```
resources/views/vendor/hyde/components/
├── colored-blockquote.blade.php
├── filepath-label.blade.php
├── markdown-heading.blade.php
└── markdown/
├── code-block-label.blade.php
├── code-block.blade.php
└── terminal.blade.php
```

Expand Down Expand Up @@ -128,24 +131,80 @@ phases, orchestrated by the `MarkdownService`:
placeholder comment so nothing downstream tries to parse their contents.
- `BladeDownProcessor` — handles single-line `[Blade]:` directives.
- `ShortcodeProcessor` — expands coloured blockquotes into rendered HTML.
- `CodeblockFilepathProcessor` — converts filepath comments into `<!-- HYDE[Filepath] -->` markers.

**2. CommonMark conversion** parses the Markdown into an abstract syntax tree and renders it.

- `TerminalExtension` is always registered. It converts matching fenced code nodes into `TerminalBlock` nodes and
renders them through the terminal view.
- Remaining fenced code nodes get their label resolved, and are wrapped in the code block view. Your highlighter still
renders the code itself.
- `HeadingRenderer` replaces CommonMark's default heading renderer with Hyde's Blade-backed one.
- Any extensions listed in `markdown.extensions` are registered here too, as is the Torchlight extension when enabled.

**3. Post-processors** run against the resulting HTML string.

- `BladeBlockProcessor` swaps the placeholders back out for the rendered Blade output.
- `CodeblockFilepathProcessor` replaces the markers with the rendered filepath label view.
- `DynamicMarkdownLinkProcessor` resolves source-file links to routes.

The distinction that matters: **AST-based blocks** (terminal, headings) are structurally aware — they only ever match
real Markdown nodes. **String-based blocks** (shortcodes, filepath labels) work on lines of text and are cheaper to
implement, but they are not fence-aware. See [Limitations](#limitations-and-gotchas).
The distinction that matters: **AST-based blocks** (code blocks, terminals, headings) are structurally aware — they
only ever match real Markdown nodes. **String-based blocks** (shortcodes, Blade blocks) work on lines of text and are
cheaper to implement, but they are not fence-aware. See [Limitations](#limitations-and-gotchas).

## Code Blocks

Fenced code blocks go through a Blade view. The view doesn't render the code itself, it receives the rendered code
block markup and decides what goes around it. Syntax highlighting is unaffected: whichever highlighter your site uses
still renders the code, and the view wraps it.

Indented code blocks are not affected.

See [Advanced Markdown](advanced-markdown#code-block-filepaths) for the filepath label syntax, both the `// filepath:`
comment and the `title` modifier on the fence.

### View contract

**View:** `hyde::components.markdown.code-block`

| Variable | Type | Description |
|-------------|-----------------------------|--------------------------------------------------------------------------------------|
| `$contents` | `string` | The rendered code block markup, as your highlighter produced it. Echo with `{!! !!}`. |
| `$language` | `string`/`null` | The fence language, or `null` when the block declared none. |
| `$label` | `HtmlString`/`string`/`null`| The resolved label, or `null` when the block set none. An `HtmlString` when `markdown.allow_html` is enabled, so the label can contain links. |

>danger `$contents` is finished markup, which is why the view echoes it unescaped. Do not re-escape it with `{{ }}` (you will see markup as text).

The block view hands the label off to its own view, so you can restyle just the label without taking over the whole
block.

**View:** `hyde::components.markdown.code-block-label`

| Variable | Type | Description |
|----------|-----------------------|-----------------------------------------------------------|
| `$path` | `HtmlString`/`string` | The label text, passed through from the block's `$label`. |

### Class hooks

| Class | Targets |
|---------------------------|--------------------------------------------|
| `hyde-code-block` | The outer `<div>` wrapping the code block |
| `hyde-code-block-label` | The filepath label |

### Customization example

Say you want a header bar above the code, showing the language next to the label:

```blade
<!-- filepath: resources/views/vendor/hyde/components/markdown/code-block.blade.php -->
<div class="hyde-code-block not-prose my-4 overflow-hidden rounded">
@if($label || $language)
<div class="flex items-center justify-between bg-gray-800 px-4 py-2 font-mono text-xs text-gray-300">
<span>{{ $label }}</span>
<span class="uppercase">{{ $language }}</span>
</div>
@endif
{!! $contents !!}
</div>
```

## Terminal Blocks

Expand Down Expand Up @@ -410,46 +469,6 @@ elements a divider rule, or render a self-linking anchor around the whole headin

>warning The heading renderer post-processes the rendered output to tidy up empty attributes and collapse newlines. Keep your markup on the conservative side — deeply nested or whitespace-sensitive structures inside the heading tag can be affected.

## Code Block Filepath Labels

A comment on the first line of a fenced code block becomes a filepath label:

````markdown
```php
‎// filepath: hello-world.php
echo 'Hello World!';
```
````

```php
// filepath: hello-world.php
echo 'Hello World!';
```

### View contract

**View:** `hyde::components.filepath-label`

| Variable | Type | Description |
|---------------------------|-----------------------|-----------------------------------------------------------------------------------|
| `$path` | `string\|HtmlString` | The label text. An `HtmlString` when `markdown.allow_html` is enabled, so the label can contain links. |
| `$highlightedByTorchlight`| `bool` | Whether the code block was highlighted by Torchlight, which needs slightly different positioning. |

The shipped view hides the label on small screens to keep it from overlapping the code. If you would rather show it on
mobile as a block above the code, that's a view change:

```blade
<!-- filepath: resources/views/vendor/hyde/components/filepath-label.blade.php -->
@props(['path', 'highlightedByTorchlight' => false])

<small class="not-prose block opacity-50 hover:opacity-100 md:float-right">
<span class="sr-only">Filepath: </span>{{ $path }}
</small>
```

This label is injected into the already-rendered HTML by a post-processor, which is why it is a plain fragment rather
than a wrapper around the code block.

## Blade Component Blocks

The blocks above are Hyde's own. The `blade component="name"` fenced block is the escape hatch that lets *any* component
Expand Down Expand Up @@ -670,7 +689,7 @@ Coloured blockquotes are expanded line by line, before the Markdown parser runs.
invisible `U+200E LEFT-TO-RIGHT MARK` character — it's the standard workaround for documenting the syntax without
triggering it.

Blocks implemented as CommonMark extensions, like terminal blocks, do not have this problem.
Blocks implemented as CommonMark extensions, like code and terminal blocks, do not have this problem.

### Coloured blockquotes are single-line

Expand All @@ -689,11 +708,11 @@ A published view is a copy, frozen at the version you published it from. Framewo
markup, add a class hook, or pass a new variable will not reach it. Re-run `php hyde publish:views components` after
major upgrades and diff your customizations against the new defaults.

### Torchlight changes the markup
### Your highlighter decides what `$contents` looks like

When Torchlight is enabled, code blocks are rendered by Torchlight rather than by CommonMark's default renderer. The
filepath label accounts for this via `$highlightedByTorchlight`, but a custom view that assumes one structure will look
wrong under the other. Test both if your site toggles Torchlight.
Torchlight and CommonMark's default renderer produce different markup for the same block, and a third-party
highlighter produces something different again. Your view receives whichever one as `$contents`, so a custom view that
digs into that markup expecting one structure will look wrong under another. Test both if your site toggles Torchlight.

## See Also

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@props(['path'])
<small class="hyde-code-block-label not-prose absolute right-4 top-3 z-10 hidden font-mono text-xs text-[color:var(--tw-prose-pre-code)] opacity-50 transition-opacity duration-250 hover:opacity-100 md:block"><span class="sr-only">Filepath: </span>{{ $path }}</small>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<div class="hyde-code-block relative">
@isset($label)
@include('hyde::components.markdown.code-block-label', ['path' => $label])
@endisset
{!! $contents !!}
</div>
Loading
Loading