Replaces maryUI and daisyUI with nonameweb/livewire-material: the Vibrant indigo scheme, a system/light/dark theme under sealshare-theme, one top app bar with the account menu, the upload drop zone and link-ready moments, M3 fields, dialogs instead of wire:confirm, snackbars instead of flashed messages, a sortable admin table, and the starter-kit cleanup. Docker builds assets after Composer; CI drops the Flux step. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
15 KiB
SealShare on Livewire Material (2.0.0)
The package itself — its decisions, the wave plan (Phases 1–10) and its tests — moved to the package repo on 2026-09-13: noNameWEB/livewire-material · docs/plans/livewire-material.md. This file keeps what SealShare does once the package reaches
1.0.0.
Goal
SealShare's UI is maryUI 2.9 on daisyUI 5 — a generic web-page look. After this change it runs
on nonameweb/livewire-material ^1.0: a clean, calm indigo Material 3 Expressive app with
a top app bar, light / dark / system theme, and two Expressive moments — the upload drop zone
and "link ready" — shipped as SealShare 2.0.0.
Context
Stacks. SealShare: Laravel 13.31, Livewire 4.4, maryUI 2.9.10 (no prefix), daisyUI 5.7,
Tailwind 4.3, Pest 5.1, Octane on FrankenPHP, PHP 8.5; public on GitHub under MIT, image
published to ghcr.io/surtic86/sealshare. ReStride: same Laravel / Livewire / Tailwind / Pest,
private on gitea.nonameweb.ch, CI through Gitea act_runner.
SealShare's UI surface (inventory, 2026-09-13):
- maryUI tags:
button30,input18,password16,icon14,card9 (6actionsslots),menu/menu-item1/4 (settings nav),theme-toggle3,toggle2,select2,modal2,table1 (:headers :rows :sort-by with-pagination,@scope),textarea1,toast1 (never triggered). - Raw daisyUI:
btn(+-primary/-ghost/-sm/-xs/-error/-outline/-disabled),alert×6,card/card-body(4 admin stat tiles),join(2 copy fields),progress×2,loading×2,badge-success/-error,divider,link link-primary×5,label,file-input,checkbox; tokensbg-base-*,border-base-300,text-error/success,border-primary(/50),bg-primary/5; rawtext-green-600,bg-white(QR code). Secondary text isopacity-50/60/70. - 20 Heroicons (outline), through
blade-heroiconspulled in transitively by maryUI. - No
Mary\PHP coupling. Admin settings flashessession('message')into an alert (AdminSettings.php:116,128,135). 3wire:confirm. - Layouts:
layouts/app→app/sidebar(centeredmax-w-5xl+ footer nav), used by the Livewire pages and all settings SFCs (config/livewire.php:47);layouts/auth→auth/simple. The theme script sits outside<head>and hard-codes dark, while maryUI's toggle defaults from the OS.partials/headloads Instrument Sans from fonts.bunny.net. - Dead:
/dashboard(starter placeholder, and Fortify'shome),welcome,pages/auth/register(still referenced byFortify::registerView,FortifyServiceProvider.php:52),layouts/app/header,layouts/auth/{card,split},components/app-logo,components/desktop-user-menu,components/placeholder-pattern; thealpinejsnpm dependency; the Flux credentials step intests.ymlanddocker.yml. - Settings
profileandpasswordshow "Saved." throughcomponents/action-message, listening forprofile-updated/password-updated;partials/settings-headinguses a daisyUIdivider. The 3wire:confirmare admin settings (remove logo, clear system password) and admin dashboard (delete share).AdminDashboard::headers()exists only for maryUI's table. - Tests assert text only, never markup; no browser tests.
- Docker: the image's caches run in
docker/entrypoint.sh(config:cache,route:cache,view:cache);docker/dev-entrypoint.shrunsnpm run buildagainst the host's mountedvendor/without acomposer install. The Flux credentials step is intests.yml,docker.ymlandlint.yml. - Screens: setup, system password, upload, share created, share download, admin dashboard, admin settings, settings (profile, password, appearance, two-factor), Fortify pages (login, forgot, reset, 2FA challenge, confirm, verify email). Stock Laravel error pages and mails.
Constraints found.
- SealShare's
Dockerfilebuilds assets (stage 1) beforecomposer install(stage 2); CSS imported fromvendor/needs the order swapped. - Laravel replaces the
errorsview namespace at render time withconfig('view.paths')+/errorsand the framework's own (Illuminate/Foundation/Exceptions/RegisterErrorViewPaths.php), so error views a package adds withaddNamespace('errors', …)are wiped; only a path inview.pathssurvives. - The package lives at
https://gitea.nonameweb.ch/noNameWEB/livewire-material.git(public, anonymous reads verified 2026-09-13).
Decisions
The package's decisions are in its own plan. SealShare's:
- Converts after
1.0.0, in one pass, by hand (~150 tags; no codemod), on branchmaterial, released as 2.0.0. - Moving SealShare to Gitea is a separate plan — this plan works wherever it is hosted.
- Seed
#4f46e5(the favicon's indigo), Vibrant — chosen after comparing it with Tonal Spot on the upload page in both themes (2026-09-13): Tonal Spot read grey-lavender on this seed. - Theme default
system, storage keysealshare-theme, legacymary-themeadopted once. Appearance is a Light / Dark / System connected button group. - One top app bar everywhere — logo and site title; a theme toggle for guests, an avatar account menu (Upload, Admin dashboard, Admin settings, Settings, theme, Log out) for users; centered content; Admin and Settings sub-pages as secondary tabs (menu picker on a phone); auth pages a centered card under the same bar. No rail, no bottom bar.
- Expressive components plus two hero moments — an Expressive shape behind the upload icon
that morphs while files are dragged over, the wavy progress indicator for uploads, a
shape-backed check when the link is ready; admin stats count up once. Instant under
prefers-reduced-motion. - The public download page uses no anchored components (no menus, no tooltips) — it must work for recipients on iOS below 18.4.
- Starter-kit cleanup during the conversion — delete the placeholder
/dashboard, point Fortifyhomeat the admin dashboard, delete the unused views and theregisterViewbinding, dropalpinejsfrom npm and the Flux step from CI. - Confirmations become M3 basic dialogs (the 3
wire:confirm) — the browser's native confirm cannot be themed and reads as a different app. (Not asked in the interview; object in review if you prefer the native confirm.) - Save feedback becomes a snackbar through the package's
Toastsconcern — admin settings' flashedsession('message')alert and settings' "Saved."action-messagealike. (Follows from the snackbar; not asked separately.) - The font is self-hosted — the fonts.bunny.net request goes, which also suits a privacy-minded self-hosted app.
- Tests: updated feature tests, the package's guard as
DesignLanguageTest, Livewire tests for changed behaviour, and four browser tests withpestphp/pest-plugin-browser(new dev dependency, approved).
Out of scope
- ReStride adopting the package — its own plan, after
1.0.0. - Moving SealShare's repository, CI and image registry to Gitea — its own plan.
- Everything the package plan puts out of scope.
- Changes to SealShare's features, routes or information architecture beyond the cleanup above.
Implementation steps
Step numbers continue the original plan's, so references elsewhere stay valid.
Phase 11 — SealShare 2.0.0 (after 1.0.0)
- Branch
materialfrommain; open the PR so CI runs. - Dependencies. Add the
vcsrepository andcomposer require nonameweb/livewire-material:^1.0;composer remove robsontenorio/mary(dropsblade-heroiconswith it);npm remove daisyui alpinejs;composer require --dev pestphp/pest-plugin-browser. maryUI goes first because its class components would shadow the package's same-named anonymous ones; the branch is therefore red from here until step 44, which is accepted — it merges once, green (Decisions: one pass). - CI and Docker. Remove the Flux credentials step from
.github/workflows/tests.yml,docker.ymlandlint.yml; install Playwright browsers intests.yml.Dockerfile: run the Composer stage first andCOPY --from=vendor /app/vendor ./vendorinto the Node stage beforenpm run build.docker/dev-entrypoint.sh: runcomposer installwhenvendor/is missing, beforenpm run build. Noicons:cacheanywhere: the package draws its symbols without blade-icons. - Styles and scheme.
resources/css/app.css:@import 'tailwindcss', the package entry fromvendor/,./material-scheme.css,@source '../views'and the package's views; drop the daisyUI plugin, maryUI and pagination@sources and the swap safelist.resources/js/app.jsimports the package JS. Runphp artisan material:scheme "#4f46e5" --variant=tonal-spot; generate Vibrant to a temporary output, compare on the upload page in both themes, commit the chosen one. - Head and theme.
partials/head: remove fonts.bunny.net; include<x-theme-script />before@vite(it currently sits outside<head>). Publish the config withtheme.default = system,storage_key = sealshare-theme,legacy_keys = ['mary-theme']. - Layouts. Rebuild
layouts/app.blade.php(absorbingapp/sidebar):<x-app-bar>withapp-logo-icon/ branding logo and site title,<x-theme-toggle>for guests or<x-account-menu>for users (Upload, Admin dashboard, Admin settings, Settings, theme, Log out throughApp\Livewire\Actions\Logout), centered content,<x-toast>.layouts/auth.blade.php(absorbingauth/simple): the same bar and a centered card. - Cleanup. Delete the
/dashboardroute,dashboard.blade.php,placeholder-pattern,welcome,pages/auth/registerand itsFortify::registerViewline,layouts/app/{header,sidebar},layouts/auth/{card,split,simple},app-logo,desktop-user-menu. Fortifyhome→/admin/dashboard. UpdateAuthenticationTest:22andEmailVerificationTest:32,63to the new redirect;DashboardTestis rewritten to assert that a signed-in admin lands on the admin dashboard and/dashboardis gone (replacing its placeholder tests, approved in the interview).RegistrationTeststays. - Public pages.
livewire/file-uploader: drop zone with<x-shape>behind the upload icon morphing whiledragging, existing Alpine folder walking andlivewire-upload-*wiring kept, wavy<x-progress>,<x-loading>for processing, selected files as<x-list>, Share Options<x-card>(<x-toggle>,<x-select>, number<x-input>s),<x-alert>for storage full, filled primary "Create Share Link".share-created: shape-backed check,<x-input copyable>for the link, four<x-stat>, info<x-alert>, "Upload More".share-download: password<x-card>with<x-password>, files as<x-list>with download icon buttons, "Download All" — no menus or tooltips.system-password-prompt,setup-wizardonto fields and buttons. - Auth pages (
login,forgot-password,reset-password,two-factor-challenge,confirm-password,verify-email): fields,<x-checkbox>for remember me,linkutility for text links,auth-session-statusonto<x-alert>(dropstext-green-600). - Settings.
pages/settings/layout→<x-section-nav>;partials/settings-headingdrops the daisyUI divider for<x-divider>;profileandpasswordshow "Saved." as a snackbar throughToasts(theprofile-updated/password-updateddispatches stay for any listener) andcomponents/action-messageis deleted;appearance→ Light / Dark / System<x-group>on$store.theme(the only toggle on the page);two-factor→<x-badge>status,<x-modal fullscreen>setup with the QR on a white token surface,<x-input copyable>key, recovery codes;delete-user-form→<x-modal>with adangeraction. - Admin.
admin-dashboard: four<x-stat>(counting up once), disk usage<x-progress>, hand-written<x-table>with<x-sort-header>and pagination (the@scopecells become plain Blade andAdminDashboard::headers()goes), view and delete icon buttons, delete confirmation in a basic<x-modal>instead ofwire:confirm.admin-settings: cards,<x-textarea>,<x-file>for the logo with preview,<x-toggle>,<x-select>,<x-input suffix>; "Remove the logo?" and "Remove the system password?" become basic dialogs instead ofwire:confirm;AdminSettingsusesToastsinstead ofsession()->flash('message')(3 places) and the alert block goes. Keep every existingdata-testattribute on the element that now plays its role. - Error pages and mail. Confirm the package's error views render in SealShare's theme;
set
config/mail.phpmarkdown.themetolivewire-material::mail.theme; check the password-reset and verify-email mails. - Guards.
tests/Feature/DesignLanguageTest.phpusingDesignGuardoverresources/viewsandapp/— no maryUI, no daisyUI, only declared colours, only existing icons. A grep forbase-content|bg-base|btn|maryreturns nothing. - Rules and AI.
php artisan boost:update --discoverto install the package guideline and skill;record-rulefor SealShare: the scheme is regenerated withmaterial:scheme, never hand-edited; the download page stays free of anchored components; the theme key. - Docs. README tech stack and the "Dark Mode" feature line; CHANGELOG
2.0.0. - Ship. Full suite green on the PR; merge; tag
v2.0.0(publishes the image throughdocker.yml).
Testing
- Feature tests updated where redirects or text change:
AuthenticationTest,EmailVerificationTest,DashboardTest(rewritten),AdminSettingsTest(asserts the toast is dispatched instead of the flash),TwoFactorAuthenticationTest,AdminDashboardTest,ShareDownloadTest. DesignLanguageTestthrough the package guard.- Livewire tests: admin settings save/remove-logo/clear-password dispatch toasts; profile and
password updates dispatch the "Saved." toast (
ProfileUpdateTest,PasswordUpdateTest); delete share, remove logo and clear system password go through their dialogs' confirm actions. - Browser tests (
tests/Browser): upload by drop and by Browse → progress → share created → copy link; the password-protected download page at 393px; admin table sort and delete dialog; a first visit follows the OS theme and Appearance switches it. - Narrow runs per step; the full suite on the PR's CI.
Risks and open questions
- Scope and time. The whole catalogue (~45 components plus extras) comes before SealShare
changes at all, so its starter-kit bugs (the placeholder
/dashboard) stay until then. Mitigation: waves tagged0.x, each reviewed in the showcase; SealShare keeps working meanwhile. - Gitea becomes a build dependency. Every SealShare CI run and Docker build fetches the
package from
gitea.nonameweb.ch; an outage or a sign-in setting reverting breaks builds. Mitigation: dist archives cached by Composer in CI; revisit Packagist if it bites. - iOS / Safari below 18.4. Anchored menus and tooltips do not position there. Mitigation:
SealShare's download page uses none; native
<select>stays the fallback everywhere. - Scheme and spring values are tuned by eye; Tonal Spot may read washed out on indigo — the Vibrant comparison in step 37 is the check.