Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nova Welcome Card Laravel Package

digital-creative/nova-welcome-card

Add a customizable welcome card to your Laravel Nova dashboard. digital-creative/nova-welcome-card lets you display a friendly greeting, supporting copy, and helpful quick links so users can get oriented and start working faster. Easy to configure and designed to fit Nova's UI.

View on GitHub
Deep Wiki
Context7

Getting Started

digital-creative/nova-welcome-card is a drop-in replacement for Nova's built-in Laravel\Nova\Cards\Help card, with the content (title, body, links) exposed as a fluent API instead of one opaque Markdown string. Day to day, you use it exactly once per project: to put a branded "start here" panel on the dashboard.

1. Install

composer require digital-creative/nova-welcome-card

Check the repo's dist/ folder first — if it ships compiled assets, no publish step is needed (the service provider registers them). If the README mentions vendor:publish, run it with the tag it documents:

php artisan vendor:publish --provider="DigitalCreative\NovaWelcomeCard\CardServiceProvider"

2. Where to look first

  • src/NovaWelcomeCard.php (or similarly named class) — this is the whole API surface. Read every public function returning $this; that's your configurable option list. Treat the README as a hint, the class as the source of truth.
  • resources/js/components/*.vue — tells you what the card actually renders and which meta keys it reads. If a fluent setter only writes withMeta('foo', ...), the Vue file confirms how foo is consumed.
  • composer.json — confirm the Nova version constraint before upgrading Nova; these thin wrapper cards break silently when Nova renames CSS classes or meta keys.

3. First use case

Swap Nova's default Help card for this one on your main dashboard so every new developer/teammate lands on the same set of links (docs, staging URL, Slack channel, changelog):

// app/Nova/Dashboards/Main.php  (Nova 4/5)
use DigitalCreative\NovaWelcomeCard\NovaWelcomeCard;

public function cards(): array
{
    return [
        NovaWelcomeCard::make()
            ->title('Welcome to ' . config('app.name'))
            ->text('Start with the onboarding doc, then grab a ticket from the board.')
            ->links([
                'Onboarding doc' => 'https://notion.so/…',
                'Staging'        => 'https://staging.example.com',
                'Changelog'      => '/nova/resources/changelogs',
            ])
            ->width('1/2'),

        // …your metrics cards
    ];
}

If you're still on a single NovaServiceProvider::cards() array (Nova 3 style or a custom dashboard), the same block goes there verbatim.

Implementation Patterns

Replace, don't duplicate. The card exists to absorb Nova's default Help card. Whenever you see Laravel\Nova\Cards\Help::make() in a dashboard, delete it — two "help" panels on one dashboard is the most common review comment you'll get.

Environment-aware content. The most valuable pattern: point links at the right place per environment without touching the dashboard class.

NovaWelcomeCard::make()
    ->title('Welcome')
    ->links(array_filter([
        'Production' => app()->isProduction() ? 'https://app.example.com' : null,
        'Staging'    => 'https://staging.example.com',
        'Local docs' => app()->isLocal() ? '/docs/README.md' : null,
    ]))
    ->canSee(fn ($request) => $request->user()->isInternal());

Per-audience cards. Register one card per role rather than one crowded card, and gate each with canSee(). Nova evaluates canSee server-side per request, so the dashboard payload stays clean (no hidden link leakage in the nova-api/dashboards/{key} response).

NovaWelcomeCard::make()->title('Admin runbook')->links([...])->canSee(fn ($r) => $r->user()->admin),
NovaWelcomeCard::make()->title('Your first week')->links([...])->canSee(fn ($r) => $r->user()->isNew()),

Keep long content out of the dashboard class. If the setter accepts Markdown/HTML strings, load them from a config file or a resources/views/partials/welcome.md and render once:

->text(Str::markdown(file_get_contents(resource_path('markdown/welcome.md'))))

That keeps copy edits in a PR reviewable by non-developers and out of PHP.

Wrap it in your own class. With 5 stars and 0 dependents, assume you may outgrow or need to patch it. Subclass once so a future swap is a one-file change:

// app/Nova/Cards/Welcome.php
class Welcome extends NovaWelcomeCard
{
    public function __construct()
    {
        parent::__construct();
        $this->title(config('app.name'))->width('1/2');
    }
}

Localization. Anything user-facing here is dashboard chrome — wrap titles and link labels in __('nova.welcome.*') so nova:translate / your lang files cover it. Fluent setters that take plain strings are easy to forget.

Compose with metrics. Put the welcome card first at 1/2 or 1/3 width, then let value/metric cards fill the rest. Nova lays cards out in insertion order per row; the welcome card is the natural top-left anchor.

Smoke-test it. Add one feature test asserting the card renders for a user and is absent for a user without permission:

$this->actingAs($user)->get('/nova-api/dashboards/main')
    ->assertOk()
    ->assertSee('Welcome');

That single test catches 90% of the breakage you'll hit on Nova upgrades.

Gotchas and Tips

  • Wrong dashboard. Nova 4+ resolves cards from the Dashboard class returned by NovaServiceProvider::dashboards() (usually Main). Adding the card to cards() when your users land on Main via the dashboard class does nothing. Verify which dashboard is the default for the user's role.
  • canSee runs per request. Don't put a DB query in the closure without eager-loading or caching — Nova may resolve cards more than once per page load (dashboard fetch + menu). Cache the role lookup on the user model.
  • Markdown vs. HTML. Nova's Help card sanitizes and renders Markdown. Raw <script>, style="...", and sometimes even <a target="_blank"> get stripped. If your links don't render as links, you're passing HTML where Markdown is expected — use [label](url) syntax or the package's dedicated links() setter.
  • Curly braces get interpolated. Content flows into a Vue component; a literal {{ $var }} in your copy may be compiled away or throw. Escape braces and @ signs in code samples you put in the card body.
  • Hardcoded colors break dark mode. Use Nova's CSS custom properties (var(--colors-primary-500), var(--colors-gray-500)) rather than hex values, or the card will look fine in light mode and unreadable in dark mode.
  • Asset caching after upgrade. If the card renders blank or unstyled after a composer update, run php artisan nova:publish --force and php artisan view:clear. In production, a stale public/vendor/nova or CDN-cached dist/js is almost always the culprit.
  • Pin the version. With one release and no dependents, ^1.0 in composer.json (not *) plus a lock file is the difference between a routine update and a broken dashboard. Watch the repo's issues after each Nova major release.
  • Debugging a missing card. Open the browser network tab and inspect the nova-api/dashboards/{key} JSON response — the card's component and meta are visible there. If the card is in the payload but invisible on screen, it's a Vue/CSS problem; if it's absent, it's canSee or dashboard registration.
  • Width quirks. Nova only supports 1/2, 1/3, 1/4, and full. Anything else silently collapses to full and will look odd next to metric cards — which are typically 1/3.
  • Extension points. If the package publishes views, publish and override the Blade partial rather than editing vendor/. If it doesn't, override component() in a subclass and point at your own Vue component — Nova will resolve it from resources/js/components in your app.
  • Escape hatch. If the package goes stale, Nova's built-in Help card with a Markdown string covers 80% of this functionality, and a 30-line custom Card subclass covers the rest. Don't let a 5-star convenience wrapper become load-bearing infrastructure.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console