The share created page gets "Show QR code", a dialog with the link as a
QR code (black on white, full screen on a phone) that downloads as a PNG
drawn in the browser, with a password reminder for protected shares; and
"Share…", which opens the device's share sheet where there is one. Both
carry only the link.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
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
Livewire's temporary upload rule was hard-coded to max:4194304 (4 GB),
so /livewire/upload-file rejected any larger file no matter how high
PHP_UPLOAD_MAX_FILESIZE or the admin's max file size were set.
_uploadErrored() then replaced Livewire's actual message with "file
exceeds the maximum size of N MB", quoting the admin limit the file was
under.
The cap is removed: PHP's upload_max_filesize is the hard limit and the
admin setting is still enforced in updatedFiles() and createShare(). A
rejected upload now logs the real validation errors and tells the user
the server could not accept the file.
max_upload_time is configurable via LIVEWIRE_MAX_UPLOAD_TIME, and the
README documents every limit large uploads depend on.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XYnWFt9pJEwvAmNFN38XD
The `uploading` flag was only cleared by `x-init="uploading = false"` on the
file list, which Alpine runs when the element is initialized. Adding a second
batch of files to the same share only patches that existing element, so the
flag stayed true forever: the spinner never went away, the drop zone stayed
disabled and the submit button stayed disabled, making the share impossible
to create.
`updatedFiles()` now dispatches `files-processed`, which runs for every batch,
and the form resets its upload state on that event instead.
Also fixes two adjacent bugs in the drag & drop path: `uploadMultiple()` was
called without callbacks so dropped files showed no progress at all, and
`relativePaths` was replaced instead of appended, shifting every earlier
file's path onto the wrong file on a second drop.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Laravel 13 upgrade pulled Pint 1.27.1 to 1.29.3, which changed the
laravel preset's default rules. composer lint and the CI lint job fail
without this, so it is required rather than cosmetic.
Formatting only, applied by `vendor/bin/pint`. The rules that fired were
fully_qualified_strict_types, ordered_imports, single_blank_line_at_eof,
unary_operator_spaces, not_operator_with_successor_space, braces_position,
single_line_empty_body, single_line_after_imports and no_extra_blank_lines.
Kept separate from the upgrade commit to keep that diff reviewable.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ZipStream writes via fwrite(php://output) which FrankenPHP silently
drops, resulting in 0-byte ZIP downloads. Switch to ZipArchive to build
the ZIP as a temp file on disk, then serve with response()->download().
- Rewrite download() to use ZipArchive + BinaryFileResponse
- Remove decryptFileToCallback() from FileEncryptionService
- Update tests for BinaryFileResponse instead of StreamedResponse
- Remove maennchen/zipstream-php dependency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>