A share can now hold a private text (a password, a key, a short note) with its files or on its own. The upload page's new "Private text" card takes up to 100 KB; the browser encrypts the text and sends it through the same chunk pipeline as a file, flagged is_text on share_files, so it gets the share's password, expiry, download limit and cleanup. The recipient sees the text only after pressing "Show text", which counts as their download, so a messenger link preview cannot use up a share limited to one download. The text is left out of the file list, the ZIP and the file counts; the admin dashboard marks shares that hold one with "Text". The website gains a Private text feature card and a fifth phone screenshot; every screenshot is retaken. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
95 lines
4.6 KiB
PHP
95 lines
4.6 KiB
PHP
<x-page :title="__('Share Created!')" :description="__('Your share is ready')">
|
|
{{-- The link is ready: a check on an Expressive shape that settles in (share-ready, app.css). --}}
|
|
<x-slot:mark>
|
|
<div class="share-check">
|
|
<x-shape name="soft-burst" class="share-check-shape" />
|
|
<x-icon name="check" size="48" class="share-check-icon" />
|
|
</div>
|
|
</x-slot:mark>
|
|
|
|
<x-stack gap="space200">
|
|
{{-- Besides the link: a QR code in a dialog, saved as a PNG in the browser, and the device's
|
|
share sheet where there is one (resources/js/share-created.js). Both carry the link only. --}}
|
|
<x-stack
|
|
gap="space100"
|
|
x-data="shareActions({
|
|
url: {{ \Illuminate\Support\Js::from($shareUrl) }},
|
|
title: {{ \Illuminate\Support\Js::from($siteTitle) }},
|
|
filename: {{ \Illuminate\Support\Js::from('share-'.$share->token.'.png') }},
|
|
messages: {{ \Illuminate\Support\Js::from(['shareFailed' => __('The share sheet could not open.'), 'downloadFailed' => __('The QR code could not be saved.')]) }},
|
|
})"
|
|
data-test="share-actions"
|
|
>
|
|
<x-input
|
|
:label="__('Share Link')"
|
|
:value="$shareUrl"
|
|
readonly
|
|
copyable
|
|
mono
|
|
icon="link"
|
|
data-test="share-link"
|
|
/>
|
|
|
|
{{-- Only on the visit the upload redirects to: the password is flashed once (FileUploader::createShare).
|
|
Masked, with the link's copy button at its end, so it is copied without reaching the screen. --}}
|
|
@if ($password)
|
|
<x-input
|
|
type="password"
|
|
:label="__('Password')"
|
|
:value="$password"
|
|
:hint="__('Available only this once. Send it separately from the link.')"
|
|
readonly
|
|
copyable
|
|
icon="key"
|
|
autocomplete="off"
|
|
data-test="share-password"
|
|
/>
|
|
@endif
|
|
|
|
<x-row gap="space100" wrap>
|
|
<x-button :label="__('Show QR code')" icon="qr_code_2" variant="tonal" x-on:click="open = true" data-test="show-qr-code" />
|
|
|
|
<span x-show="canShare" x-cloak>
|
|
<x-button :label="__('Share…')" icon="share" variant="tonal" x-on:click="share()" data-test="share-sheet" />
|
|
</span>
|
|
</x-row>
|
|
|
|
<x-modal fullscreen :title="__('Scan to open the share')" data-test="qr-code-dialog">
|
|
<x-stack gap="space200">
|
|
{{-- The quiet zone is baked into the SVG (App\Services\QrCodeService), white in
|
|
either theme so a scanner keeps its contrast; the container adds no colour. --}}
|
|
<div data-qr-code class="share-qr">{!! $qrCodeSvg !!}</div>
|
|
|
|
@if ($share->isPasswordProtected())
|
|
<x-alert color="info" icon="lock" :title="__('Recipients also need the password.')" />
|
|
@endif
|
|
</x-stack>
|
|
|
|
<x-slot:actions>
|
|
<x-button :label="__('Close')" x-on:click="close()" />
|
|
<x-button :label="__('Download')" icon="download" variant="tonal" x-on:click="downloadQrCode($el.closest('dialog').querySelector('[data-qr-code] svg'))" data-test="download-qr-code" />
|
|
</x-slot:actions>
|
|
</x-modal>
|
|
</x-stack>
|
|
|
|
<x-grid :columns="2" gap="space200">
|
|
<x-stat :title="__('Files')" :value="$share->files->where('is_text', false)->count()" icon="description" />
|
|
<x-stat :title="__('Total Size')" :value="Number::fileSize($share->total_size)" icon="hard_drive" />
|
|
<x-stat :title="__('Expires')" :value="$share->expires_at ? $share->expires_at->diffForHumans() : __('Never')" icon="schedule" />
|
|
<x-stat :title="__('Max Downloads')" :value="$share->max_downloads ?? __('Unlimited')" icon="download" />
|
|
|
|
@if ($share->hasText())
|
|
<x-stat :title="__('Private text')" :value="Number::fileSize($share->textFile->file_size)" icon="notes" />
|
|
@endif
|
|
</x-grid>
|
|
|
|
@if ($share->isPasswordProtected())
|
|
<x-alert color="info" icon="lock" :title="__('This share is password protected')" />
|
|
@endif
|
|
|
|
<x-row justify="end">
|
|
<x-button :label="__('Upload More')" :link="route('upload')" icon="add" variant="tonal" />
|
|
</x-row>
|
|
</x-stack>
|
|
</x-page>
|