diff --git a/app/Http/Controllers/TrainingRoadmapPdfController.php b/app/Http/Controllers/TrainingRoadmapPdfController.php new file mode 100644 index 000000000..72899ccd0 --- /dev/null +++ b/app/Http/Controllers/TrainingRoadmapPdfController.php @@ -0,0 +1,51 @@ +get(self::ROADMAP_SOURCE); + + if (! $response->successful()) { + abort(502, 'Unable to load roadmap PDF.'); + } + + return $response->body(); + } + ); + + return response($bytes, 200, [ + 'Content-Type' => 'application/pdf', + 'Content-Disposition' => 'inline; filename="DDP_toolkit_roadmap.pdf"', + 'Cache-Control' => 'public, max-age=3600', + ]); + } + + /** + * Minimal PDF.js viewer (no site chrome) for iframe embedding on training pages. + */ + public function viewer() + { + return response() + ->view('training.roadmap-pdfjs') + ->header('X-Frame-Options', 'SAMEORIGIN'); + } +} diff --git a/app/Nova/TrainingResource.php b/app/Nova/TrainingResource.php index 93c404fe6..d907c53b5 100644 --- a/app/Nova/TrainingResource.php +++ b/app/Nova/TrainingResource.php @@ -6,8 +6,10 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\URL; use Laravel\Nova\Fields\Boolean; +use Laravel\Nova\Fields\FormData; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\Number; +use Laravel\Nova\Fields\Select; use Laravel\Nova\Fields\Text; use Laravel\Nova\Fields\Textarea; use Laravel\Nova\Fields\Trix; @@ -153,10 +155,38 @@ public function fields(Request $request): array ->nullable() ->help('Optional scroll offset in pixels for in-page anchor links (useful with sticky headers).'), + Select::make('Roadmap embed format', 'roadmap_embed_kind') + ->options([ + 'pdf' => 'PDF (inline viewer)', + 'svg' => 'SVG (paste markup below)', + 'none' => 'None (remove placeholder output)', + ]) + ->default('pdf') + ->help('Use [[embed_roadmap_pdf]] or [[embed_roadmap]] in Content where the roadmap should appear.'), + Text::make('Roadmap PDF embed URL', 'roadmap_pdf_embed_url') ->nullable() ->rules('nullable', 'url') - ->help('Optional HTTPS URL to a PDF shown inline in the Roadmap section. Put the literal text [[embed_roadmap_pdf]] in Content where the embed should appear (avoids Nova stripping iframes).'), + ->dependsOn(['roadmap_embed_kind'], function (Text $field, NovaRequest $request, FormData $formData) { + if (($formData->roadmap_embed_kind ?? 'pdf') === 'pdf') { + $field->show(); + } else { + $field->hide(); + } + }) + ->help('HTTPS URL to the roadmap PDF. Used when format is PDF.'), + + Textarea::make('Roadmap SVG', 'roadmap_svg') + ->nullable() + ->rows(10) + ->dependsOn(['roadmap_embed_kind'], function (Textarea $field, NovaRequest $request, FormData $formData) { + if (($formData->roadmap_embed_kind ?? 'pdf') === 'svg') { + $field->show(); + } else { + $field->hide(); + } + }) + ->help('Full markup from your design tool. Used when format is SVG.'), Text::make('Button text', 'button_text')->nullable(), diff --git a/app/TrainingResource.php b/app/TrainingResource.php index 56a438517..fabc3255c 100644 --- a/app/TrainingResource.php +++ b/app/TrainingResource.php @@ -35,6 +35,8 @@ class TrainingResource extends Model 'about_box_section', 'anchor_offset', 'roadmap_pdf_embed_url', + 'roadmap_embed_kind', + 'roadmap_svg', 'button_text', 'button_url', 'secondary_button_text', diff --git a/database/migrations/2026_05_01_140000_add_roadmap_embed_kind_and_svg_to_training_resources_table.php b/database/migrations/2026_05_01_140000_add_roadmap_embed_kind_and_svg_to_training_resources_table.php new file mode 100644 index 000000000..b698d5a50 --- /dev/null +++ b/database/migrations/2026_05_01_140000_add_roadmap_embed_kind_and_svg_to_training_resources_table.php @@ -0,0 +1,23 @@ +string('roadmap_embed_kind', 16)->default('pdf')->after('roadmap_pdf_embed_url'); + $table->mediumText('roadmap_svg')->nullable()->after('roadmap_embed_kind'); + }); + } + + public function down(): void + { + Schema::table('training_resources', function (Blueprint $table) { + $table->dropColumn(['roadmap_embed_kind', 'roadmap_svg']); + }); + } +}; diff --git a/database/seeders/TrainingResourceDiscoverDigitalProgrammeSeeder.php b/database/seeders/TrainingResourceDiscoverDigitalProgrammeSeeder.php index ba3063414..44c1695d5 100644 --- a/database/seeders/TrainingResourceDiscoverDigitalProgrammeSeeder.php +++ b/database/seeders/TrainingResourceDiscoverDigitalProgrammeSeeder.php @@ -91,6 +91,8 @@ public function run(): void HTML, 'anchor_offset' => 120, 'roadmap_pdf_embed_url' => 'https://codeweek-resources.s3.eu-west-1.amazonaws.com/+discover-digital-toolkit/DDP_toolkit_roadmap.pdf', + 'roadmap_embed_kind' => 'pdf', + 'roadmap_svg' => null, 'third_button_text' => 'Register an activity', 'third_button_url' => 'https://codeweek.eu/add?skip=1', 'meta_title' => 'Discover Digital Programme - Toolkit', diff --git a/resources/views/training/partials/roadmap-pdf-embed.blade.php b/resources/views/training/partials/roadmap-pdf-embed.blade.php index 219dd8d95..c037de629 100644 --- a/resources/views/training/partials/roadmap-pdf-embed.blade.php +++ b/resources/views/training/partials/roadmap-pdf-embed.blade.php @@ -1,17 +1,28 @@ @props([ 'url', ]) +@php + // Strip any fragment from stored URL for the "open in new tab" link. + $tabUrl = \Illuminate\Support\Str::before($url, '#'); + // Same-origin PDF.js viewer for the allowlisted DDP roadmap (see TrainingRoadmapPdfController). + // Other URLs keep the direct PDF iframe with viewer chrome hints. + $ddpRoadmapBase = 'https://codeweek-resources.s3.eu-west-1.amazonaws.com/+discover-digital-toolkit/DDP_toolkit_roadmap.pdf'; + $usePdfjsViewer = strtolower(rtrim($tabUrl, '/')) === strtolower(rtrim($ddpRoadmapBase, '/')); + $fragment = '#toolbar=0&navpanes=0&scrollbar=1&view=FitH'; + $embedSrc = $usePdfjsViewer ? route('training.roadmap_pdf_viewer') : $tabUrl.$fragment; +@endphp
- + {{ __('Open roadmap PDF in a new tab') }} — {{ __('if the preview does not load in your browser.') }} diff --git a/resources/views/training/partials/roadmap-svg-embed.blade.php b/resources/views/training/partials/roadmap-svg-embed.blade.php new file mode 100644 index 000000000..f6582e5bb --- /dev/null +++ b/resources/views/training/partials/roadmap-svg-embed.blade.php @@ -0,0 +1,6 @@ +@props([ + 'svg', +]) +