happones/kinetix
happones/kinetix is a Laravel/PHP package by happones. See the repository README for its features, installation steps, configuration options, and usage examples, and review it to confirm compatibility and suitability for your project.
Kinetix is a Laravel + Vue package whose documented surface is narrower than its "Hybrid-Driven Framework" tagline: three Vue components (<KinetixAccessibilityPanel>, <KinetixAccessibilityMenu>, <KinetixModeToggle>) plus best-effort server persistence of per-user preferences. Budget your first hour for reading the source in vendor/happones/kinetix before you install it anywhere real — with 2 stars and no dependents, the source is the documentation.
Minimal path, run through Sail:
vendor/bin/sail composer require happones/kinetix
vendor/bin/sail artisan vendor:publish --provider="Happones\\Kinetix\\KinetixServiceProvider"
vendor/bin/sail npm run dev
Then, in order:
composer show happones/kinetix for the version, look for src/, resources/js/, and any tailwind preset or CSS file. If it ships a tailwind.config.js preset, stop — you're on Tailwind 4 (CSS-first, @custom-variant dark) and that preset will not apply.resources/js/vendor/kinetix folder determines everything downstream. Register it in vite.config.js the same way the package README or source suggests.<KinetixModeToggle /> into resources/js/layouts/AppLayout.vue (or your authenticated layout), then open the app and toggle Light/Dark/System. If nothing changes, your Tailwind 4 dark variant isn't wired to the class the package writes — that's the whole ballgame, fix it before touching the a11y panel.<KinetixAccessibilityMenu /> on the Fortify login page and <KinetixAccessibilityPanel /> behind a settings route. Those three placements cover the documented capability.Do not adopt the "framework" framing. There is no routing, navigation, or state layer worth surrendering to this package, and your stack already has Inertia v3, Wayfinder, Fortify, and Reverb as the sources of truth.
Wrap every component before you use it. Create resources/js/components/kinetix/ with thin local wrappers:
<!-- resources/js/components/kinetix/ThemeToggle.vue -->
<script setup lang="ts">
import { KinetixModeToggle } from '...'
</script>
<template>
<KinetixModeToggle />
</template>
Call sites import your wrapper. When the package breaks on a Tailwind 4 upgrade (it will), or you fork it, you edit one file, not forty pages. This is the single highest-leverage pattern for a package at this adoption level.
Layout-level placement, not page-level. Theme and preference state is orthogonal to Inertia page props. Mount the toggle once in AppLayout.vue and the guest menu once in AuthLayout.vue / the login view. Keep it out of resources/js/pages/* so page components stay presentational and testable.
Persistence is your work, not the package's. Expect to add:
users, or a user_preferences side table if you anticipate growth),PATCH /preferences route behind auth for the authenticated path,Use vendor/bin/sail artisan route:list --except-vendor when auditing routes — vendor routes will otherwise clutter your output and Wayfinder will generate functions for them.
Own the hydration path. The package's client-side components will read stored preferences; your job is that <html class="dark"> is already correct before hydration. Do this in the root Blade template with a tiny inline script reading a cookie (never localStorage alone — the server can't see it):
<script>
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark')
}
</script>
Then treat the Vue component as a controller for that state, not the source of truth.
Guest → authenticated promotion. Best-effort guest persistence means: store in cookie/localStorage while anonymous, then on login POST the stored values once and clear the client copy. Write a Pest feature test asserting the promotion happens exactly once and that a guest write cannot forge a user ID.
Pin hard. "happones/kinetix": "1.0.3" — exact version, no caret. If the maintainer force-pushes or deletes the repo, add a repositories VCS entry pinned to a commit SHA, or vendor the components outright. At 0 dependents, upstream breakage is a build failure on your Monday morning.
Code-split the panel. The accessibility panel is settings-page furniture; it should not be in the login bundle. Dynamic import() inside your wrapper's <script setup> keeps it out of the critical path.
darkMode: 'class' in tailwind.config.js. Tailwind 4 is CSS-first. Verify the package toggles a class your @custom-variant dark (&:where(.dark, .dark *)) actually responds to. If it writes data-theme="dark", you need your own variant — not a package bug, an integration gap.@inertiajs/vite. A component that reads localStorage during render produces hydration mismatch warnings, not just a visual flash. Assert browser-logs is clean after a hard reload on a deep link in dark mode.throttle:preferences), keep CSRF on, and validate with an enum — never store arbitrary JSON from an anonymous request.Inertia::lazy() / LazyProp are gone. If the package's JS uses axios directly or the PHP side returns lazy props, it predates your stack. Grep vendor/happones/kinetix for both before merging.route:list --except-vendor and --only-vendor are your friends; Wayfinder generating typed functions for vendor routes is harmless but noisy in diffs.dd() inside its service provider, console.log inside its components, and read the compiled output in public/build. Don't hunt for docs; there aren't any.config/kinetix.php for the actual knobs (storage key, cookie name, default mode, component prefix). Bind overrides in a KinetixServiceProvider extension in your own AppServiceProvider rather than editing vendor files, so composer update doesn't eat your changes.How can I help you explore Laravel packages today?