# 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](https://gitea.nonameweb.ch/noNameWEB/livewire-material/src/branch/main/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: `button` 30, `input` 18, `password` 16, `icon` 14, `card` 9 (6 `actions` slots), `menu`/`menu-item` 1/4 (settings nav), `theme-toggle` 3, `toggle` 2, `select` 2, `modal` 2, `table` 1 (`:headers :rows :sort-by with-pagination`, `@scope`), `textarea` 1, `toast` 1 (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`; tokens `bg-base-*`, `border-base-300`, `text-error/success`, `border-primary(/50)`, `bg-primary/5`; raw `text-green-600`, `bg-white` (QR code). Secondary text is `opacity-50/60/70`. - 20 Heroicons (outline), through `blade-heroicons` pulled in transitively by maryUI. - No `Mary\` PHP coupling. Admin settings flashes `session('message')` into an alert (`AdminSettings.php:116,128,135`). 3 `wire:confirm`. - Layouts: `layouts/app` → `app/sidebar` (centered `max-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* `` and hard-codes dark, while maryUI's toggle defaults from the OS. `partials/head` loads Instrument Sans from fonts.bunny.net. - Dead: `/dashboard` (starter placeholder, and Fortify's `home`), `welcome`, `pages/auth/register` (still referenced by `Fortify::registerView`, `FortifyServiceProvider.php:52`), `layouts/app/header`, `layouts/auth/{card,split}`, `components/app-logo`, `components/desktop-user-menu`, `components/placeholder-pattern`; the `alpinejs` npm dependency; the Flux credentials step in `tests.yml` and `docker.yml`. - Settings `profile` and `password` show "Saved." through `components/action-message`, listening for `profile-updated` / `password-updated`; `partials/settings-heading` uses a daisyUI `divider`. The 3 `wire:confirm` are 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.sh` runs `npm run build` against the host's mounted `vendor/` without a `composer install`. The Flux credentials step is in `tests.yml`, `docker.yml` **and** `lint.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 `Dockerfile` builds assets (stage 1) **before** `composer install` (stage 2); CSS imported from `vendor/` needs the order swapped. - Laravel **replaces** the `errors` view namespace at render time with `config('view.paths')` + `/errors` and the framework's own (`Illuminate/Foundation/Exceptions/RegisterErrorViewPaths.php`), so error views a package adds with `addNamespace('errors', …)` are wiped; only a path in `view.paths` survives. - 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 branch `material`, 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 key `sealshare-theme`, legacy `mary-theme` adopted 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 Fortify `home` at the admin dashboard, delete the unused views and the `registerView` binding, drop `alpinejs` from 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 `Toasts` concern — admin settings' flashed `session('message')` alert and settings' "Saved." `action-message` alike. *(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** with `pestphp/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`) 34. **Branch** `material` from `main`; open the PR so CI runs. 35. **Dependencies.** Add the `vcs` repository and `composer require nonameweb/livewire-material:^1.0`; `composer remove robsontenorio/mary` (drops `blade-heroicons` with 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). 36. **CI and Docker.** Remove the Flux credentials step from `.github/workflows/tests.yml`, `docker.yml` and `lint.yml`; install Playwright browsers in `tests.yml`. `Dockerfile`: run the Composer stage first and `COPY --from=vendor /app/vendor ./vendor` into the Node stage before `npm run build`. `docker/dev-entrypoint.sh`: run `composer install` when `vendor/` is missing, before `npm run build`. No `icons:cache` anywhere: the package draws its symbols without blade-icons. 37. **Styles and scheme.** `resources/css/app.css`: `@import 'tailwindcss'`, the package entry from `vendor/`, `./material-scheme.css`, `@source '../views'` and the package's views; drop the daisyUI plugin, maryUI and pagination `@source`s and the swap safelist. `resources/js/app.js` imports the package JS. Run `php artisan material:scheme "#4f46e5" --variant=vibrant` (chosen over Tonal Spot after comparing both on the upload page in both themes). 38. **Head and theme.** `partials/head`: remove fonts.bunny.net; include `` before `@vite` (it currently sits outside ``). Publish the config with `theme.default = system`, `storage_key = sealshare-theme`, `legacy_keys = ['mary-theme']`. 39. **Layouts.** Rebuild `layouts/app.blade.php` (absorbing `app/sidebar`): `` with `app-logo-icon` / branding logo and site title, `` for guests or `` for users (Upload, Admin dashboard, Admin settings, Settings, theme, Log out through `App\Livewire\Actions\Logout`), centered content, ``. `layouts/auth.blade.php` (absorbing `auth/simple`): the same bar and a centered card. 40. **Cleanup.** Delete the `/dashboard` route, `dashboard.blade.php`, `placeholder-pattern`, `welcome`, `pages/auth/register` and its `Fortify::registerView` line, `layouts/app/{header,sidebar}`, `layouts/auth/{card,split,simple}`, `app-logo`, `desktop-user-menu`. Fortify `home` → `/admin/dashboard`. Update `AuthenticationTest:22` and `EmailVerificationTest:32,63` to the new redirect; `DashboardTest` is rewritten to assert that a signed-in admin lands on the admin dashboard and `/dashboard` is gone (replacing its placeholder tests, approved in the interview). `RegistrationTest` stays. 41. **Public pages.** `livewire/file-uploader`: drop zone with `` behind the upload icon morphing while `dragging`, existing Alpine folder walking and `livewire-upload-*` wiring kept, wavy ``, `` for processing, selected files as ``, Share Options `` (``, ``, number ``s), `` for storage full, filled primary "Create Share Link". `share-created`: shape-backed check, `` for the link, four ``, info ``, "Upload More". `share-download`: password `` with ``, files as `` with download icon buttons, "Download All" — no menus or tooltips. `system-password-prompt`, `setup-wizard` onto fields and buttons. 42. **Auth pages** (`login`, `forgot-password`, `reset-password`, `two-factor-challenge`, `confirm-password`, `verify-email`): fields, `` for remember me, `link` utility for text links, `auth-session-status` onto `` (drops `text-green-600`). 43. **Settings.** `pages/settings/layout` → ``; `partials/settings-heading` drops the daisyUI divider for ``; `profile` and `password` show "Saved." as a snackbar through `Toasts` (the `profile-updated` / `password-updated` dispatches stay for any listener) and `components/action-message` is deleted; `appearance` → Light / Dark / System `` on `$store.theme` (the only toggle on the page); `two-factor` → `` status, `` setup with the QR on a white token surface, `` key, recovery codes; `delete-user-form` → `` with a `danger` action. 44. **Admin.** `admin-dashboard`: four `` (counting up once), disk usage ``, hand-written `` with `` and pagination (the `@scope` cells become plain Blade and `AdminDashboard::headers()` goes), view and delete icon buttons, delete confirmation in a basic `` instead of `wire:confirm`. `admin-settings`: cards, ``, `` for the logo with preview, ``, ``, ``; "Remove the logo?" and "Remove the system password?" become basic dialogs instead of `wire:confirm`; `AdminSettings` uses `Toasts` instead of `session()->flash('message')` (3 places) and the alert block goes. Keep every existing `data-test` attribute on the element that now plays its role. 45. **Error pages and mail.** Confirm the package's error views render in SealShare's theme; set `config/mail.php` `markdown.theme` to `livewire-material::mail.theme`; check the password-reset and verify-email mails. 46. **Guards.** `tests/Feature/DesignLanguageTest.php` using `DesignGuard` over `resources/views` and `app/` — no maryUI, no daisyUI, only declared colours, only existing icons. A grep for `base-content|bg-base|btn|mary` returns nothing. 47. **Rules and AI.** `php artisan boost:update --discover` to install the package guideline and skill; `record-rule` for SealShare: the scheme is regenerated with `material:scheme`, never hand-edited; the download page stays free of anchored components; the theme key. 48. **Docs.** README tech stack and the "Dark Mode" feature line; CHANGELOG `2.0.0`. 49. **Ship.** Full suite green on the PR; merge; tag `v2.0.0` (publishes the image through `docker.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`. - `DesignLanguageTest` through 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 tagged `0.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 `