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
2 changes: 1 addition & 1 deletion dist/pertuk.css

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions dist/pertuk.js

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions resources/js/pertuk.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,8 @@ class DocsManager {
const ensureIndex = async () => {
if (index) return index;
try {
const res = await fetch("/docs/index.json", {
const indexUrl = input.getAttribute("data-index-url") || "/docs/index.json";
const res = await fetch(indexUrl, {
headers: { Accept: "application/json" },
});
const data = await res.json();
Expand Down Expand Up @@ -299,12 +300,14 @@ class DocsManager {
return;
}

const baseUrl = input.getAttribute("data-base-url") || "/docs";

results.innerHTML = items
.slice(0, 8)
.map((it) => {
const href = it.anchor
? `/docs/${it.slug}#${it.anchor}`
: `/docs/${it.slug}`;
? `${baseUrl}/${it.slug}#${it.anchor}`
: `${baseUrl}/${it.slug}`;
const displayTitle = it.heading
? `${it.title} > ${it.heading}`
: it.title;
Expand Down
50 changes: 49 additions & 1 deletion resources/views/components/header.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,20 @@ class="flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br fro
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</div>
@php
$currentLocale = app()->getLocale();
$currentVersion = $current_version ?? null;

$searchIndexUrl = $currentVersion
? route('pertuk.docs.version.search.json', ['version' => $currentVersion, 'locale' => $currentLocale])
: route('pertuk.docs.search.json', ['locale' => $currentLocale]);

$searchBaseUrl = url('/' . config('pertuk.route_prefix', 'docs') . ($currentVersion ? '/' . $currentVersion : '') . '/' . $currentLocale);
@endphp
<input id="docs-search-input" type="search" placeholder="{{ __('Search documentation...') }}"
aria-label="{{ __('Search documentation') }}"
data-index-url="{{ $searchIndexUrl }}"
data-base-url="{{ $searchBaseUrl }}"
class="w-full rounded-lg border border-gray-300 bg-gray-50/50 ps-10 pe-4 py-2.5 text-sm placeholder-gray-500 outline-none transition-all duration-200 focus:border-orange-500 focus:bg-white focus:ring-2 focus:ring-orange-500/20 dark:border-gray-700 dark:bg-gray-900/50 dark:text-white dark:placeholder-gray-400 dark:focus:border-orange-400 dark:focus:bg-gray-900 dark:focus:ring-orange-400/20"
autocomplete="off" />
<div class="absolute inset-y-0 end-0 pe-3 flex items-center pointer-events-none">
Expand All @@ -45,6 +57,42 @@ class="absolute top-full mt-2 hidden max-h-96 w-full overflow-auto rounded-lg bo

<!-- Navigation -->
<div class="flex items-center gap-4">
<!-- Context Switcher (Desktop) -->
<div class="hidden lg:flex items-center gap-1 mr-4 border-r border-gray-200 dark:border-gray-800 pr-4">
@php
// Identify top-level contexts for navigation
$navContexts = collect($items ?? [])->map(function($item) {
$parts = explode('/', $item['slug']);
return count($parts) > 1 ? $parts[0] : 'General';
})->unique();

// Current context
$currentContext = 'General';
if(isset($slug)) {
$parts = explode('/', $slug);
$currentContext = count($parts) > 1 ? $parts[0] : 'General';
}
@endphp

@foreach($navContexts as $context)
@if($context !== 'General')
@php
// Find the index page or first page of this context to link to
$firstDoc = collect($items ?? [])->first(function($item) use ($context) {
return str_starts_with($item['slug'], $context . '/');
});
$linkUrl = $firstDoc
? route('pertuk.docs.show', ['locale' => app()->getLocale(), 'slug' => $firstDoc['slug']])
: '#';
@endphp
<a href="{{ $linkUrl }}"
class="px-3 py-1.5 text-sm font-medium rounded-md transition-colors {{ $currentContext === $context ? 'text-orange-600 bg-orange-50 dark:text-orange-400 dark:bg-orange-900/20' : 'text-gray-600 hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:text-white dark:hover:bg-gray-800' }}">
{{ ucfirst(str_replace('-', ' ', $context)) }}
</a>
@endif
@endforeach
</div>

<!-- Global Language Selector -->
<div class="hidden md:block">
<label for="global-lang-select" class="sr-only">{{ __('Language') }}</label>
Expand All @@ -68,7 +116,7 @@ class="rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm font-mediu
$versions = \Xoshbin\Pertuk\Services\DocumentationService::getAvailableVersions();
$currentVersion = $current_version ?? config('pertuk.default_version');
$currentLocale = app()->getLocale();
$currentSlug = $slug ?? 'index';
$currentSlug = $currentSlug ?? $slug ?? 'index';
$routePrefix = config('pertuk.route_prefix', 'docs');
@endphp
@if(count($versions) > 0)
Expand Down
27 changes: 12 additions & 15 deletions resources/views/components/pertuk-layout.blade.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
@props(['title' => null, 'currentLocale' => null, 'currentVersion' => null, 'slug' => null])
@props(['title' => null, 'currentLocale' => null, 'currentVersion' => null, 'slug' => null, 'items' => []])

@php
$locale = $currentLocale ?? app()->getLocale();
$isRtl = in_array($locale, config('pertuk.rtl_locales', ['ar', 'ckb']));
$current_version = $currentVersion; // Pass through to included header
@endphp
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', $locale) }}" dir="{{ $isRtl ? 'rtl' : 'ltr' }}" class="h-full">
<html lang="{{ str_replace('_', '-', $locale) }}" dir="{{ $isRtl ? 'rtl' : 'ltr' }}" class="h-full antialiased">

<head>
<meta charset="utf-8">
Expand All @@ -22,29 +22,26 @@
class="skip-link bg-orange-600 text-white px-4 py-2 rounded focus:outline-none focus:ring-2 focus:ring-orange-500">Skip
to content</a>

@include('pertuk::components.header', ['current_version' => $current_version])
@include('pertuk::components.header', ['current_version' => $current_version, 'slug' => $slug, 'items' => $items])

<div class="mx-auto max-w-8xl px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-1 gap-8 lg:grid-cols-12 lg:gap-12 py-8">
<!-- Fluid container for ERP-scale documentation -->
<div class="mx-auto max-w-[1920px] px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-1 lg:grid-cols-[18rem_1fr] xl:grid-cols-[18rem_1fr_18rem] gap-8 py-8 items-start">
<!-- Sidebar -->
<aside class="hidden lg:block lg:col-span-3 lg:order-1" aria-label="Navigation">
<div class="sticky top-24 max-h-[calc(100vh-6rem)] overflow-y-auto">
{{ $sidebar ?? '' }}
</div>
<aside class="hidden lg:block lg:sticky top-24 max-h-[calc(100vh-6rem)] overflow-y-auto pr-4 z-40 bg-white dark:bg-gray-950 lg:bg-transparent" aria-label="Navigation">
{{ $sidebar ?? '' }}
</aside>

<!-- Main Content -->
<main id="main" class="col-span-1 lg:col-span-6 xl:col-span-6 lg:order-2 min-w-0">
<main id="main" class="min-w-0">
<div class="min-w-0">
{{ $slot }}
</div>
</main>

<!-- Table of Contents -->
<aside class="hidden xl:block xl:col-span-3 lg:order-3" aria-label="On this page">
<div class="sticky top-24 max-h-[calc(100vh-6rem)] overflow-y-auto">
{{ $toc ?? '' }}
</div>
<!-- Table of Contents (Right Sidebar) -->
<aside class="hidden xl:block sticky top-24 max-h-[calc(100vh-6rem)] overflow-y-auto pl-4" aria-label="On this page">
{{ $toc ?? '' }}
</aside>
</div>
</div>
Expand Down
107 changes: 60 additions & 47 deletions resources/views/components/sidebar.blade.php
Original file line number Diff line number Diff line change
@@ -1,81 +1,94 @@
@php
/** @var array<int,array{slug:string,title:string}> $items */
/** @var string $active */

// Group items by category for better organization
$groupedItems = collect($items)->groupBy(function ($item) {
// 1. Determine Current Context
$activeParts = explode('/', $active ?? '');
$currentContext = count($activeParts) > 1 ? $activeParts[0] : 'General';

// 2. Filter Items for Context
$contextItems = collect($items)->filter(function ($item) use ($currentContext) {
$parts = explode('/', $item['slug']);
return count($parts) > 1 ? $parts[0] : 'Getting Started';
$itemContext = count($parts) > 1 ? $parts[0] : 'General';
return $itemContext === $currentContext;
});

// 3. Group by Sub-category (if exists) or fallback to 'Main'
$groupedItems = $contextItems->groupBy(function ($item) use ($currentContext) {
// Remove context from slug to find sub-category
$relSlug = $currentContext === 'General' ? $item['slug'] : substr($item['slug'], strlen($currentContext) + 1);

if (empty($relSlug)) {
return 'Main';
}

$parts = explode('/', $relSlug);

return (count($parts) > 1 && !empty($parts[0])) ? $parts[0] : 'Main';
});

// Sort groups: 'Main' first, then alphabetical or bespoke order
$groupedItems = $groupedItems->sortBy(function ($items, $key) {
return $key === 'Main' ? '000' : $key;
});

$locale = app()->getLocale();
$isRtl = in_array($locale, config('pertuk.rtl_locales', ['ar', 'ckb']));
$routePrefix = config('pertuk.route_prefix', 'docs');
@endphp

<nav class="space-y-6">
<nav class="space-y-6" x-data="{ search: '' }">
<!-- Sidebar Search -->
<div class="mb-4">
<div class="relative">
<div class="absolute inset-y-0 start-0 ps-3 flex items-center pointer-events-none">
<svg class="h-4 w-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
</div>
<input type="text"
x-model="search"
placeholder="{{ __('Filter navigation...') }}"
class="w-full rounded-md border border-gray-300 bg-white px-3 py-1.5 ps-9 text-sm text-gray-900 focus:border-orange-500 focus:outline-none focus:ring-1 focus:ring-orange-500 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:focus:ring-orange-500/50"
>
</div>
</div>

@foreach ($groupedItems as $category => $categoryItems)
<div class="space-y-3">
@if ($category !== 'Getting Started' || $groupedItems->count() > 1)
<h3 class="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 px-3">
<div class="space-y-2" x-show="!search || $el.textContent.toLowerCase().includes(search.toLowerCase())">
@if ($category !== 'Main' || $groupedItems->count() > 1)
<h3 class="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 px-3 truncate" title="{{ str_replace('-', ' ', ucfirst($category)) }}">
{{ str_replace('-', ' ', ucfirst($category)) }}
</h3>
@endif

<ul class="space-y-1">
<ul class="space-y-0.5">
@foreach ($categoryItems as $item)
@php
$isActive = ($active ?? '') === $item['slug'];
$displayTitle = $item['title'];

// Clean up title if it contains category prefix
// Cleanup title: remove context/category prefixes for cleaner sidebar
if (str_contains($item['title'], ':')) {
$displayTitle = trim(explode(':', $item['title'], 2)[1] ?? $item['title']);
$parts = explode(':', $item['title']);
$displayTitle = trim(end($parts));
}
@endphp

<li>
<a href="{{ url('/' . config('pertuk.route_prefix', 'docs') . '/' . $locale . '/' . $item['slug']) }}"
class="group flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors duration-200 @if ($isActive) bg-orange-50 text-orange-700 dark:bg-orange-900/20 dark:text-orange-400 @else text-gray-700 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-white @endif"
<li x-show="!search || '{{ strtolower($displayTitle) }}'.includes(search.toLowerCase())">
<a href="{{ url('/' . $routePrefix . '/' . $locale . '/' . $item['slug']) }}"
class="group flex items-center rounded-md px-3 py-1.5 text-sm font-medium transition-colors duration-200 border-l-2 {{ $isActive ? 'border-orange-500 bg-orange-50 text-orange-700 dark:bg-orange-900/20 dark:text-orange-400' : 'border-transparent text-gray-600 hover:text-gray-900 hover:bg-gray-50 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-200' }}"
@if ($isActive) aria-current="page" @endif>
@if ($isActive)
<svg class=" h-2 w-2 flex-shrink-0 text-orange-500" fill="currentColor" viewBox="0 0 8 8">
<circle cx="4" cy="4" r="3" />
</svg>
@endif


<span class="truncate">{{ $displayTitle }}</span>

@if ($isActive)
<svg class="{{ $isRtl ? 'mr-auto rotate-180' : 'ml-auto' }} h-4 w-4 flex-shrink-0 text-orange-500"
fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 5l7 7-7 7" />
</svg>
@endif
</a>
</li>
@endforeach
</ul>
</div>
@endforeach

<!-- Quick Links Section -->
<div class="border-t border-gray-200 dark:border-gray-700 pt-6 space-y-3">
<h3 class="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 px-3">
Quick Links
</h3>

<ul class="space-y-1">
<li>
<a href="https://github.com/your-repo" target="_blank" rel="noopener noreferrer"
class="group flex items-center rounded-md px-3 py-2 text-sm font-medium text-gray-700 transition-colors duration-200 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-white">
<svg class=" h-4 w-4 flex-shrink-0 text-gray-400 group-hover:text-gray-500" fill="currentColor"
viewBox="0 0 24 24">
<path
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.30.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
</svg>
<span>GitHub</span>
</a>
</li>
</ul>

<div x-show="search && $el.previousElementSibling.children.length === 0" class="px-3 text-sm text-gray-500 dark:text-gray-400 text-center py-4">
{{ __('No results found') }}
</div>
</nav>
Loading