Core
TourWelcome
The block a tour opens with — what it is about, and the choice between starting it now and being asked again later.
On this page
The block a Tour opens with: a card in the middle of the screen saying what the walkthrough covers, and two buttons — start it, or be asked again later. Reach for it when a tour is long enough that beginning it uninvited would be an interruption. Without one, a tour starts by dimming the page and pointing at something, which is what it has always done.
use NyonCode\WireCore\Tours\TourWelcome;
How It Works
When it is shown. The browser plans the tour first — which steps have an
element on this page — and only then greets. A tour whose steps are all missing
does not start, so it does not greet either. The card is shown only when the
tour is starting from the top: somebody carried onto this page by a step's
on(), or coming back to a walkthrough they
left halfway, is returned to where they were without being asked whether to
start something already running.
The two answers.
- Start closes the card and begins the walkthrough at the first step. Nothing is recorded — finishing or skipping it later records it, as always.
- Later closes the tour and records a postponement: the tour is not offered again for the rest of that session, and the person is asked again on their next visit.
Later is not Skip. The walkthrough's own Skip is final — it is stored exactly as finishing is, because somebody who skipped has decided. Later is the answer that had no way of being said before: not now, ask again.
Postponements are counted, and run out. A greeting that came back for ever
would be worse than one that never asked. Each Later increments a count, and the
one that reaches the tour's postpone() limit acknowledges
the tour instead — the same record Skip writes, so nothing downstream has a
fourth state to handle. The default limit is 3, configurable as
wire-core.tours.postpone. ->postpone(0) removes the Later button entirely,
leaving a card that can only be started.
Why a session and not a clock. The postponement is stamped with the id of
the session it was made in, and holds only while that session does. That is what
makes "later" mean the same thing on every driver: on session the entry would
have expired anyway, while on database it outlives the sitting, and without the
comparison a postponement there would be indistinguishable from a skip. No
duration to configure, and no clock to get wrong across time zones.
Where it runs. The card is markup the page already carried, shown and hidden by Alpine. Only Later makes a request, to record the postponement. Escape dismisses the card and means the same as Later — and for a tour that allows no postponement, it closes the card without recording anything, so the tour greets again on the next visit.
Traps.
- A count survives a version bump, but not a finish. Finishing, skipping and
replaying all clear the postponement and its count. Changing
since()starts the count again too, because a count kept against an older version would mean the author's third greeting is somebody else's first. - The labels are resolved when the page renders, not when the tour is
registered. A tour is registered in a service provider's
boot(), and a translation resolved there is in whatever locale the console had. Leavestart()andlater()unset to get the framework's translated wording. - The card needs the layout that draws it, like the rest of the tour. See Tour → Your own layout.
Basic Usage
Tour::make('getting-started') ->welcome( TourWelcome::make() ->heading('Welcome aboard') ->text('A minute, and you will know where everything is.'), ) ->steps([ TourStep::make('admin-sidebar')->text('Every area of the application is here.'), ]);
Content
heading() is the bold line, text() the sentence or two under it. Both are
plain text, and either can be left out. Translate them as you would any other
string:
TourWelcome::make() ->heading(__('tours.welcome.heading')) ->text(__('tours.welcome.text'));
The Buttons
Both labels are optional, and both fall back to the framework's translated wording — which is usually what you want, because restating it in every tour is how one of them ends up in the wrong language:
TourWelcome::make() ->start('Show me around') // default: "Start the tour" ->later('Not just now'); // default: "Maybe later"
The Later button is drawn only when the tour allows a postponement. These two are the same statement — a card that can only be started:
Tour::make('one-step')->postpone(0)->welcome(TourWelcome::make()->heading('New in 2.2'));
How Often It Asks Again
postpone() is on the Tour, not here: how many times a
walkthrough may be put off is a property of the walkthrough rather than of the
card that offers it.
Tour::make('getting-started')->postpone(5); // five "later"s, then it stops asking
Left unset, the configured default applies:
// config/wire-core.php'tours' => [ 'postpone' => env('WIRE_TOURS_POSTPONE', 3),],
Your Own Markup
When what you want is different markup rather than different styling — an
illustration, a logo, a short video — view() replaces the framework's card
outright:
TourWelcome::make() ->heading('Welcome aboard') ->view('tours.welcome');
The view is included inside the tour's own Alpine scope, and that scope is the whole contract:
| Name | What it is |
|---|---|
greeting |
Whether the card should be showing. The view owns its own visibility — nothing shows it for you |
begin() |
Start the walkthrough |
later() |
Close it, and record a postponement if the tour allows one |
welcome |
The resolved payload: heading, text, start, later (null when postponing is off) |
It also receives $welcome (this object) and $tour, for anything you would
rather render on the server:
{{-- resources/views/tours/welcome.blade.php --}}<div x-show="greeting" x-cloak class="fixed inset-0 z-[63] grid place-items-center p-4"> <div class="w-full max-w-md rounded-2xl bg-white p-8 text-center shadow-2xl dark:bg-gray-800"> <img src="/img/welcome.svg" alt="" class="mx-auto mb-4 h-24"> <h2 class="text-lg font-semibold">{{ $welcome->getHeading() }}</h2> <p class="mt-2 text-sm text-gray-600 dark:text-gray-300">{{ $welcome->getText() }}</p> <div class="mt-6 flex justify-center gap-2"> <button type="button" x-show="welcome.later" x-text="welcome.later" x-on:click="later()"></button> <button type="button" x-text="welcome.start" x-on:click="begin()"></button> </div> </div></div>
A view is the escape hatch for markup, not for behaviour: when the card appears, and what Later costs, stay with the tour.
Styling
The framework's card carries element hooks, so most changes need no view at all:
| Hook | Element |
|---|---|
tour-welcome |
The centred overlay |
tour-welcome-heading, tour-welcome-text |
The two lines |
tour-welcome-start, tour-welcome-later |
The two buttons |
[data-wire="tour-welcome"] > div { @apply max-w-lg rounded-3xl; }[data-wire="tour-welcome-start"] { @apply bg-emerald-600 hover:bg-emerald-700; }
Extended Example
A first-run tour that asks before it starts, allows two postponements, and says what it is about in the application's own words.
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider;use NyonCode\WireCore\Tours\Tour;use NyonCode\WireCore\Tours\Tours;use NyonCode\WireCore\Tours\TourStep;use NyonCode\WireCore\Tours\TourWelcome; class AppServiceProvider extends ServiceProvider{ public function boot(): void { $this->app->make(Tours::class)->register( Tour::make('getting-started') ->postpone(2) ->welcome( TourWelcome::make() ->heading('Two minutes, and you will know your way around') ->text('We will point at four things and then leave you to it.') ->start('Show me') ->later('Not just now'), ) ->steps([ TourStep::make('admin-sidebar') ->heading('Everything lives here') ->text('Each area of the application has an entry in this menu.') ->placement('right-start'), TourStep::make('global-search-trigger') ->text('Or jump straight to any record.'), ]), ); }}
Somebody who chooses "Not just now" is asked again on their next visit, and once more after that. The third time would be a fourth greeting, so instead the tour records itself as seen and stops — they can still bring it back from Replay the tour in the user menu.
TourWelcome API
TourWelcome::make() // no arguments — everything about it is optional->heading(?string $heading) // the bold line — default none->text(?string $text) // the body, plain text — default none->start(?string $start) // label of the start button — default __('wire-core::messages.tour_start')->later(?string $later) // label of the postpone button — default __('wire-core::messages.tour_later')->view(?string $view) // render this view instead of the framework's card — default none->getHeading(): ?string->getText(): ?string->getStart(): ?string // the author's label, or null for the framework's->getLater(): ?string->getView(): ?string
Related
- Tour — who sees a tour, where it runs, and how
postpone()is counted - TourStep — what each stop points at
- Configuration — the default postponement allowance
- Theming → Styling hooks — what an element hook promises