Files
SealShare/docs/plans/livewire-material.md
T
Andreas Reinhold / reiniandClaude Opus 5 c4a17b65c8 Move SealShare onto Livewire Material
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
2026-09-13 10:49:38 +02:00

224 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SealShare on Livewire Material (2.0.0)
> The package itself — its decisions, the wave plan (Phases 110) 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* `<head>` 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=tonal-spot`; generate Vibrant to a
temporary output, compare on the upload page in both themes, commit the chosen one.
38. **Head and theme.** `partials/head`: remove fonts.bunny.net; include `<x-theme-script />`
before `@vite` (it currently sits outside `<head>`). 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`): `<x-app-bar>` with
`app-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 through `App\Livewire\Actions\Logout`), centered content, `<x-toast>`.
`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 `<x-shape>` behind the upload
icon morphing while `dragging`, existing Alpine folder walking and `livewire-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-wizard` onto fields and buttons.
42. **Auth pages** (`login`, `forgot-password`, `reset-password`, `two-factor-challenge`,
`confirm-password`, `verify-email`): fields, `<x-checkbox>` for remember me, `link` utility
for text links, `auth-session-status` onto `<x-alert>` (drops `text-green-600`).
43. **Settings.** `pages/settings/layout``<x-section-nav>`; `partials/settings-heading`
drops the daisyUI divider for `<x-divider>`; `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 `<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 a `danger` action.
44. **Admin.** `admin-dashboard`: four `<x-stat>` (counting up once), disk usage
`<x-progress>`, hand-written `<x-table>` with `<x-sort-header>` and pagination (the
`@scope` cells become plain Blade and `AdminDashboard::headers()` goes), view and delete
icon buttons, delete confirmation in a basic `<x-modal>` instead of `wire: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 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 `<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.