Skip to content
Merged
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
10 changes: 10 additions & 0 deletions app/Http/Controllers/ShowDocumentationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ public function __invoke(Request $request, string $platform, string $version, ?s
fn () => $this->getPageProperties($platform, $version, $page)
);
} catch (InvalidArgumentException $e) {
$resolvedPage = app(DocsVersionService::class)->resolvePageForVersion($platform, $version, $page);

if ($resolvedPage !== $page && file_exists(resource_path("views/docs/{$platform}/{$version}/{$resolvedPage}.md"))) {
return redirect(route('docs.show', [
'platform' => $platform,
'version' => $version,
'page' => $resolvedPage,
]), 301);
}

return $this->redirectToFirstNavigationPage($navigation, $page);
}
$title = $pageProperties['title'].' - NativePHP '.$platform.' v'.$version;
Expand Down
15 changes: 15 additions & 0 deletions app/Livewire/VersionSwitcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Livewire;

use App\Services\DocsVersionService;
use Illuminate\View\ViewException;
use Livewire\Attributes\Locked;
use Livewire\Component;
Expand Down Expand Up @@ -34,11 +35,25 @@ public function mount(array $versions)
$this->platform = request()->route()->parameter('platform');
$this->version = request()->route()->parameter('version');
$this->page = request()->route()->parameter('page');

$prereleaseVersions = config("docs.prerelease_versions.{$this->platform}", []);

foreach ($versions as $number => $label) {
if (in_array($number, $prereleaseVersions)) {
$versions[$number] = "{$label} (beta)";
}
}

krsort($versions);

$this->versions = $versions;
}

public function updatedVersion()
{
$this->page = app(DocsVersionService::class)
->resolvePageForVersion($this->platform, $this->version, $this->page);

if (! $this->pageExists($this->platform, $this->version, $this->page)) {
$this->page = 'introduction';
}
Expand Down
4 changes: 2 additions & 2 deletions app/Services/DocsSearchService.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ public function getLatestVersions(): array
$versions = $this->getVersions();

return [
'desktop' => collect($versions['desktop'] ?? [])->sort()->last() ?? '2',
'mobile' => collect($versions['mobile'] ?? [])->sort()->last() ?? '3',
'desktop' => (string) (config('docs.latest_versions.desktop') ?? collect($versions['desktop'] ?? [])->sort()->last() ?? '2'),
'mobile' => (string) (config('docs.latest_versions.mobile') ?? collect($versions['mobile'] ?? [])->sort()->last() ?? '3'),
];
}

Expand Down
34 changes: 34 additions & 0 deletions app/Services/DocsVersionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public function determineCanonicalUrl(string $platform, string $page): string
$latestVersion = $platform === 'mobile' ? config('docs.latest_versions.mobile') : config('docs.latest_versions.desktop');

$page = $this->resolveOldVersionApisWithPluginsCorePage($platform, $latestVersion, $page);
$page = $this->resolvePageForVersion($platform, $latestVersion, $page);

$latestPagePath = resource_path("views/docs/{$platform}/{$latestVersion}/{$page}.md");

Expand All @@ -21,6 +22,39 @@ public function determineCanonicalUrl(string $platform, string $page): string
]);
}

/**
* Map a page to its equivalent path in the target version, following the
* configured renames in either direction. A page renamed in v4 resolves
* old-to-new when targeting v4 or later, and new-to-old when targeting
* anything earlier.
*/
public function resolvePageForVersion(string $platform, int|string $targetVersion, string $page): string
{
$renames = config("docs.renamed_pages.{$platform}", []);

ksort($renames);

foreach ($renames as $renamedInVersion => $map) {
if ((int) $targetVersion >= (int) $renamedInVersion && isset($map[$page])) {
$page = $map[$page];
}
}

krsort($renames);

foreach ($renames as $renamedInVersion => $map) {
if ((int) $targetVersion < (int) $renamedInVersion) {
$reversed = array_flip($map);

if (isset($reversed[$page])) {
$page = $reversed[$page];
}
}
}

return $page;
}

/**
* Handle renamed paths (e.g., apis/* moved to plugins/core/*)
*/
Expand Down
44 changes: 41 additions & 3 deletions config/docs.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
| Documentation Latest Versions
|--------------------------------------------------------------------------
|
| This configuration defines the latest version for each documentation
| platform. When a user views an older version, they will see a notice
| prompting them to view the latest version.
| This configuration defines the latest stable version for each
| documentation platform. When a user views an older version, they will
| see a notice prompting them to view the latest version. Unversioned
| docs URLs redirect here.
|
*/

Expand All @@ -18,4 +19,41 @@
'mobile' => 3,
],

/*
|--------------------------------------------------------------------------
| Documentation Pre-release Versions
|--------------------------------------------------------------------------
|
| Versions listed here are published but still in beta. They are labelled
| as beta in the version switcher, display a pre-release notice on every
| page, and are never the default version users are redirected to.
|
*/

'prerelease_versions' => [
'desktop' => [],
'mobile' => [4],
],

/*
|--------------------------------------------------------------------------
| Renamed Documentation Pages
|--------------------------------------------------------------------------
|
| Pages that were renamed in a given version, keyed by the version the
| rename happened in, mapping the old path to the new path. Used to map
| a page to its equivalent when moving between versions (in both
| directions) and to redirect stale URLs within a version.
|
*/

'renamed_pages' => [
'desktop' => [],
'mobile' => [
4 => [
'the-basics/native-components' => 'the-basics/native-ui',
],
],
],

];
51 changes: 51 additions & 0 deletions resources/views/components/docs/beta-version-notice.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
@props(['platform', 'version', 'page'])

@php
$isPrerelease = in_array((int) $version, config("docs.prerelease_versions.{$platform}", []));

if ($isPrerelease) {
$stableVersion = config("docs.latest_versions.{$platform}");
$page = app(\App\Services\DocsVersionService::class)->resolvePageForVersion($platform, $stableVersion, $page);
$stablePagePath = resource_path("views/docs/{$platform}/{$stableVersion}/{$page}.md");
$targetPage = file_exists($stablePagePath) ? $page : 'getting-started/introduction';

$stableUrl = route('docs.show', [
'platform' => $platform,
'version' => $stableVersion,
'page' => $targetPage,
]);
}
@endphp

@if ($isPrerelease)
<div
class="mb-6 flex items-start gap-3 rounded-2xl bg-yellow-50 px-5 py-4 text-yellow-900 ring-1 ring-yellow-200 dark:bg-yellow-950/40 dark:text-yellow-100 dark:ring-yellow-800/40"
role="note"
>
<svg
class="mt-0.5 size-5 shrink-0 text-yellow-600 dark:text-yellow-400"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z"
clip-rule="evenodd"
/>
</svg>
<div class="text-sm leading-relaxed">
<p class="font-semibold">You're viewing pre-release documentation &mdash; version {{ $version }}.x is in beta</p>
<p class="mt-1 text-yellow-900/80 dark:text-yellow-100/80">
Features, APIs and behaviour may change before the stable release.
<a
href="{{ $stableUrl }}"
class="font-medium underline underline-offset-2 hover:text-yellow-950 dark:hover:text-yellow-50"
>
View the stable version ({{ $stableVersion }}.x)
</a>
</p>
</div>
</div>
@endif
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
$isOldVersion = $latestVersion && (int) $version < (int) $latestVersion;

if ($isOldVersion) {
$page = app(\App\Services\DocsVersionService::class)->resolvePageForVersion($platform, $latestVersion, $page);
$latestPagePath = resource_path("views/docs/{$platform}/{$latestVersion}/{$page}.md");

// Handle renamed paths (e.g., apis/* moved to plugins/core/*)
Expand Down
6 changes: 3 additions & 3 deletions resources/views/components/plugin-toc.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@
</flux:button>

<flux:popover class="w-64">
<nav class="flex max-h-80 flex-col gap-0.5 overflow-y-auto">
<nav class="flex max-h-96 flex-col gap-0.5 overflow-y-auto">
<template x-for="heading in headings" :key="heading.tocKey">
<a
:href="'#' + heading.id"
x-on:click.prevent="document.getElementById(heading.id)?.scrollIntoView({ behavior: 'smooth', block: 'start' })"
:class="heading.level === 2 ? 'pl-2' : 'pl-5'"
class="rounded-md px-2 py-1.5 text-xs transition hover:bg-zinc-100 dark:text-white/80 dark:hover:bg-zinc-700"
:class="heading.level === 2 ? 'pl-2 font-semibold' : 'pl-5'"
class="rounded-md px-2 py-1.5 text-sm transition hover:bg-zinc-100 dark:text-white/80 dark:hover:bg-zinc-700"
x-text="heading.text"
></a>
</template>
Expand Down
20 changes: 14 additions & 6 deletions resources/views/docs/index.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
<livewire:version-switcher :versions="[
1 => '1.x',
2 => '2.x',
3 => '3.x'
3 => '3.x',
4 => '4.x'
]" />
@endif

Expand All @@ -37,6 +38,12 @@
:page="request()->route('page')"
/>

<x-docs.beta-version-notice
:platform="$platform"
:version="$version"
:page="request()->route('page')"
/>

<h1 class="text-4xl font-semibold">
{{ $title }}
</h1>
Expand All @@ -56,7 +63,8 @@
<livewire:version-switcher :versions="[
1 => '1.x',
2 => '2.x',
3 => '3.x'
3 => '3.x',
4 => '4.x'
]" />
@endif

Expand All @@ -67,22 +75,22 @@

@if (count($tableOfContents) > 0)
<div class="sticky top-20 z-10 mt-8 mb-4 flex justify-end">
<div class="rounded-full bg-white shadow-sm dark:bg-zinc-800">
<div class="mr-2 rounded-full bg-white shadow-sm dark:bg-zinc-800">
<flux:dropdown position="bottom" align="end">
<flux:button variant="filled" size="sm" class="!rounded-full">
<x-icons.stacked-lines class="size-4" />
On this page
</flux:button>

<flux:popover class="w-64">
<nav class="flex max-h-80 flex-col gap-0.5 overflow-y-auto">
<nav class="flex max-h-96 flex-col gap-0.5 overflow-y-auto">
@foreach ($tableOfContents as $item)
<a
href="#{{ $item['anchor'] }}"
x-on:click.prevent="document.getElementById('{{ $item['anchor'] }}')?.scrollIntoView({ behavior: 'smooth', block: 'start' })"
@class([
'rounded-md px-2 py-1.5 text-xs transition hover:bg-zinc-100 dark:text-white/80 dark:hover:bg-zinc-700',
'pl-2' => $item['level'] == 2,
'rounded-md px-2 py-1.5 text-sm transition hover:bg-zinc-100 dark:text-white/80 dark:hover:bg-zinc-700',
'pl-2 font-semibold' => $item['level'] == 2,
'pl-5' => $item['level'] == 3,
])
>
Expand Down
Loading
Loading