ericlagarda/nova-text-card
A simple Laravel Nova card for displaying custom text, HTML, or notes directly on your dashboard, resource pages, or detail screens—useful for instructions, summaries, and lightweight static content without building a custom Vue component.
Architecture fit: A presentation-only Nova dashboard card — not domain infrastructure. It occupies the deliberately low-coupling slot in the stack: internal admin surface used by ops, support, and back-office staff. Legitimate placements are static announcements, policy/quick links, onboarding hints, runbook pointers, and contextual banners on resource detail/edit screens ("this record is synced from billing; edits will be overwritten"). It has no bearing on customer-facing UI, public pages, or the API surface, and should never appear in a roadmap or competitive narrative. The strategic fact is the size: roughly a Card subclass (src/TextCard.php), a Vue component (resources/js/components/Card.vue), a service provider, a stub/config, and a build pipeline. That smallness makes adoption and in-house replacement equally cheap — so the real architecture question is "do we own this file set?", not "does this vendor integrate?"
Integration feasibility: Straightforward if and only if the constraint matrix lines up. Happy path is composer require ericlagarda/nova-text-card, Composer auto-discovery of EricLagarda\NovaTextCard\CardServiceProvider, and registration via NovaServiceProvider::cards() or per-dashboard dashboards(). Capability is exercised through the fluent API (title(), content(), markdown/HTML flags, alignment, width()) plus inherited Nova Card behaviors such as canSee() for role-scoped guidance — an "ops runbook" card only for ops, "billing notes" only for finance. Feasibility collapses on compatibility: last release June 2020 places it firmly in the Nova 2/3 era, while Nova 4+ moved to Vue 3 and a revised nova.mix asset pipeline, meaning Card.vue and asset registration likely need rework before the card renders at all.
Technical risk:
Card.vue renders via v-html, unsanitized user-, model-, or API-sourced content becomes an XSS vector in the admin console.content() resolves on every dashboard and detail-screen load; a query or API call placed there multiplies across requests.dist/js/card.js is stale or absent — a debugging trap that consumes TPM calendar time even when the PHP is correct.Key questions:
Stack fit: Fits Laravel + Nova only, and only on majors matching its June 2020 vintage. It is a Nova card, so it inherits Nova's provider registration, asset pipeline, and Card base class semantics — no framework-level adaptation, no middleware, no data layer. Content is authored in PHP against a fluent API, so the natural storage for copy is config, a translation file, or a resources/views/admin/ partial, keeping message text out of deploys.
Migration path: Two viable routes, and the recommendation is the second.
composer require, verify auto-discovery in bootstrap/cache/packages.php (or php artisan about), register in cards(), pin exact versions and transitive deps in composer.json. Fast, but you carry an unmaintained third-party requirement with no upstream fix path.src/ and resources/js/ into nova-components/text-card/ (or a packages/ path repository), rebuild assets against the current Nova pipeline, pin to our Nova version, and treat it as a first-party component. This reframes a dead dependency as a maintained internal asset, and removes Composer/upgrade risk for what is a small PHP class plus a tiny Vue component.Compatibility: Validate in this order: (1) Nova major and composer.json constraints; (2) whether Card.vue still compiles under the current webpack.mix/nova.mix setup; (3) whether the service provider registers assets the Nova 4/5 way; (4) whether markdown and HTML modes both render in a disposable install; (5) whether theming/dark-mode reads acceptably against current Nova chrome. Treat steps 2–3 as likely failures and budget accordingly. Pin exact versions regardless of route — a floating constraint will break on the next composer update with no upstream fix coming.
Sequencing:
README.md for the fluent contract, src/TextCard.php for actual method names, Card.vue for the v-html question.canSee() scoping, with the card removable by reverting a single provider change.Maintenance: Effectively zero upstream, total in-house. Once installed or forked, this code is ours: Nova upgrades, asset rebuilds, Vue 3 migration, and any bug fix route through our team. The mitigation is the fork itself — owning a ~40-line PHP class plus a tiny Vue component is a normal internal-tooling burden, whereas owning an unmaintained Composer requirement is an ongoing exception in dependency reviews. Budget one rebuild per Nova major upgrade; that is the recurring cost.
Support: None. No maintainer SLA, no issue triage, no security advisories, no community backstop at 20 stars and zero dependents. Internal support falls to whoever forked it, and should be documented as such — an unowned vendored component is worse than a dependency, because at least a dependency has a version number to point at. Assign a named owner at merge time.
Scaling: Trivially horizontal — the card is stateless presentation, so dashboard concurrency is Nova's problem, not the card's. The scaling risk is per-request cost, not load: content() resolves on every dashboard and detail-screen request, so any query or API call placed inside it multiplies across the whole admin population. Enforce a rule that computed content goes through short-TTL Cache::remember or is precomputed, and review any content() argument that touches the database. Card count is bounded by dashboard usability, not by the package — but each added card is another per-request resolution, so treat proliferation as a design smell.
Failure modes:
dist/js/card.js missing or stale; check browser Network tab, then Nova provider registration. Most "card is blank" reports are discovery (step 1) or asset load (step 3), not render.bootstrap/cache/packages.php and php artisan about before debugging the component.Card.vue uses v-html and content is not fully controlled, admin-session compromise is possible. Constrain HTML mode to config, translation keys, and hardcoded strings; anything user-sourced must be sanitized first.content() degrades every dashboard load at once; cache or precompute.Ramp-up: Minutes for a Nova-competent engineer — the fluent API is small and self-evident, and the documented patterns (config-driven announcements, markdown for structured notes, HTML for link lists and CTAs, width('1/2') composition for a lightweight admin home, resource-level cards() overrides for contextual banners) are copy-paste-able. Debugging ramp-up is the real cost: the ordered checklist (Composer discovery → card returned from cards() → compiled JS loaded → markdown/HTML flag correct in Card.vue → Nova version matches constraint) should be written down for whoever inherits the component. Non-developers can safely own the copy if it lives in config or translations — that is the highest-value operational pattern, since it turns a maintenance-window banner or policy notice into a config toggle with no deploy. Everything else — theming, dark mode, localization, accessibility — requires Vue and Nova asset-pipeline familiarity, which is a scarcer internal skill and should be scoped before promising any of it.
How can I help you explore Laravel packages today?