This commit is contained in:
2026-08-19 20:38:53 +02:00
parent d700ed1aa5
commit 3e4f8c80b2
5 changed files with 676 additions and 344 deletions

View File

@@ -236,138 +236,9 @@
</div>
<div id="info-modal" class="modal-overlay" style="display: none;">
<div class="modal-content" style="max-width: 500px;">
<div class="modal-body" style="padding: 20px 0; text-align: left;">
<table class="info-table">
@if(enable_item_title && can_manage_item)
<tr class="info-title-row">
<th>Title</th>
<td>
<div class="info-title-edit-wrap">
<input type="text" id="info-title-input" class="info-title-input" value="{!! item.title || '' !!}" placeholder="Add a title…" maxlength="500" data-item-id="{{ item.id }}" />
<button id="info-title-save" class="info-title-save-btn"><i class="fa-solid fa-check"></i></button>
</div>
<span id="info-title-status" class="info-title-status" style="display:none"></span>
</td>
</tr>
@elseif(enable_item_title && item.title)
<tr>
<th>Title</th>
<td>{!! item.title !!}</td>
</tr>
@endif
<tr class="info-id-row">
<th>ID</th>
<td><code>{{ item.id }}</code></td>
</tr>
<tr class="info-visibility-row">
<th>Visibility</th>
<td>
<span id="info-visibility-label" style="display: inline-flex; align-items: center; gap: 6px;">
@if(item.visibility === 2)
<i class="fa-solid fa-lock" style="color: var(--color-danger, #ff4444);"></i> Private
@elseif(item.visibility === 1)
<i class="fa-solid fa-link" style="color: var(--color-warning, #ffbb33);"></i> Unlisted
@else
<i class="fa-solid fa-globe" style="color: var(--color-success, #00C851);"></i> Public
@endif
</span>
@if(can_manage_item)
<button id="info-visibility-edit-btn" class="btn-secondary btn-sm" style="margin-left: 8px; padding: 2px 8px; font-size: 0.8em;" data-item-id="{{ item.id }}" data-visibility="{{ item.visibility || 0 }}"><i class="fa-solid fa-pen"></i> Edit</button>
@endif
</td>
</tr>
@if(enable_expiring_uploads !== false)
<tr class="info-expiry-row">
<th>Expires</th>
<td>
<div class="info-expiry-wrap" style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
<span id="info-expiry-label" style="display: inline-flex; align-items: center; gap: 6px; color: #ffaa00;" title="{{ item.expires_at ? new Date(item.expires_at * 1000).toLocaleString() : '' }}">
@if(item.expires_at)
<i class="fa-solid fa-clock"></i> {{ item.expires_in || ('in ' + new Date(item.expires_at * 1000).toLocaleString()) }}
@else
<i class="fa-solid fa-clock-slash" style="color: var(--text-muted, #888);"></i> Never
@endif
</span>
@if(can_manage_item)
<div class="info-expiry-edit-controls" style="display: inline-flex; align-items: center; gap: 6px;">
<select id="info-expiry-select" class="info-expiry-select" style="padding: 2px 6px; font-size: 0.85em; background: rgba(0,0,0,0.4); color: #fff; border: 1px solid rgba(255,255,255,0.2); border-radius: 4px;" data-item-id="{{ item.id }}">
<option value="permanent" {{ !item.expires_at ? 'selected' : '' }}>Permanent (Never)</option>
<option value="30minutes">30 Minutes</option>
<option value="1hour">1 Hour</option>
<option value="24hours">24 Hours</option>
<option value="1week">1 Week</option>
<option value="1month">1 Month</option>
</select>
<button id="info-set-expiry-btn" class="btn-secondary btn-sm" style="padding: 2px 8px; font-size: 0.8em;" data-item-id="{{ item.id }}"><i class="fa-solid fa-check"></i> Save</button>
</div>
@endif
</div>
</td>
</tr>
@endif
@include(snippets/info-modal)
<tr>
<th>{{ t('info_modal.file_size') || 'File Size' }}</th>
<td>{{ item.size }}</td>
</tr>
@if(item_has_dimensions)
<tr>
<th>{{ t('info_modal.dimensions') || 'Dimensions' }}</th>
<td>{{ item.width }} × {{ item.height }}</td>
</tr>
@endif
<tr>
<th>{{ t('info_modal.mime_type') || 'MIME Type' }}</th>
<td><code>{{ item.mime }}</code></td>
</tr>
@if(item.checksum)
<tr>
<th>{{ t('info_modal.sha256') || 'SHA-256 Hash' }}</th>
<td><pre class="info-hash-codeblock"><code style="word-break: break-all;">{{ item.checksum.split('_bypass_')[0] }}</code></pre></td>
</tr>
@endif
@if(item.show_repost_row)
<tr class="info-repost-row">
<th>Repost</th>
<td>
@each(item.reposts as rp)
@if(rp.match_type === 'phash')
<a href="/{{ rp.slug || rp.id }}" style="margin-right: 4px; opacity: 0.75;" tooltip="Visually similar (perceptual hash)" flow="up">~#{{ rp.slug || rp.id }}</a>
@else
<a href="/{{ rp.slug || rp.id }}" style="margin-right: 4px;" tooltip="Exact duplicate (checksum)" flow="up">#{{ rp.slug || rp.id }}</a>
@endif
@endeach
</td>
</tr>
@endif
<tr>
<th>{{ t('info_modal.direct_url') || 'Direct URL' }}</th>
<td>
<a href="{{ item.mime === 'video/youtube' ? 'https://www.youtube.com/watch?v=' + item.dest.replace('yt:', '') : item.dest }}" target="_blank">
{{ t('info_modal.view_file') || 'View File' }}
</a>
</td>
</tr>
@if(item.src.short)
<tr>
<th>{{ t('info_modal.source') || 'Source' }}</th>
<td><a href="{{ item.src.long }}" target="_blank" style="word-break: break-all;">{{ item.src.short }}</a></td>
</tr>
@endif
</table>
</div>
<div class="modal-actions" style="display: flex; justify-content: flex-end; gap: 10px;">
@if(can_manage_item)
<button class="btn-secondary" id="info-rethumb-btn" data-item-id="{{ item.id }}"><i class="fa-solid fa-arrows-rotate"></i> Regenerate Thumbnail</button>
@endif
<button class="btn-secondary" id="info-modal-close">{{ t('common.close') || 'Close' }}</button>
</div>
</div>
</div>
<div id="visibility-modal" class="modal-overlay" style="display: none;">
<div class="modal-content" style="max-width: 420px;">
<div class="modal-header" style="margin-bottom: 15px; border-bottom: 1px solid var(--border-color, #333); padding-bottom: 10px;">

View File

@@ -181,138 +181,9 @@
</div>
<div id="info-modal" class="modal-overlay" style="display: none;">
<div class="modal-content" style="max-width: 500px;">
<div class="modal-body" style="padding: 20px 0; text-align: left;">
<table class="info-table">
@if(enable_item_title && can_manage_item)
<tr class="info-title-row">
<th>Title</th>
<td>
<div class="info-title-edit-wrap">
<input type="text" id="info-title-input" class="info-title-input" value="{!! item.title || '' !!}" placeholder="Add a title…" maxlength="500" data-item-id="{{ item.id }}" />
<button id="info-title-save" class="info-title-save-btn"><i class="fa-solid fa-check"></i></button>
</div>
<span id="info-title-status" class="info-title-status" style="display:none"></span>
</td>
</tr>
@elseif(enable_item_title && item.title)
<tr>
<th>Title</th>
<td>{!! item.title !!}</td>
</tr>
@endif
<tr class="info-id-row">
<th>ID</th>
<td><code>{{ item.id }}</code></td>
</tr>
<tr class="info-visibility-row">
<th>Visibility</th>
<td>
<span id="info-visibility-label" style="display: inline-flex; align-items: center; gap: 6px;">
@if(item.visibility === 2)
<i class="fa-solid fa-lock" style="color: var(--color-danger, #ff4444);"></i> Private
@elseif(item.visibility === 1)
<i class="fa-solid fa-link" style="color: var(--color-warning, #ffbb33);"></i> Unlisted
@else
<i class="fa-solid fa-globe" style="color: var(--color-success, #00C851);"></i> Public
@endif
</span>
@if(can_manage_item)
<button id="info-visibility-edit-btn" class="btn-secondary btn-sm" style="margin-left: 8px; padding: 2px 8px; font-size: 0.8em;" data-item-id="{{ item.id }}" data-visibility="{{ item.visibility || 0 }}"><i class="fa-solid fa-pen"></i> Edit</button>
@endif
</td>
</tr>
@if(enable_expiring_uploads !== false)
<tr class="info-expiry-row">
<th>Expires</th>
<td>
<div class="info-expiry-wrap" style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
<span id="info-expiry-label" style="display: inline-flex; align-items: center; gap: 6px; color: #ffaa00;" title="{{ item.expires_at ? new Date(item.expires_at * 1000).toLocaleString() : '' }}">
@if(item.expires_at)
<i class="fa-solid fa-clock"></i> {{ item.expires_in || ('in ' + new Date(item.expires_at * 1000).toLocaleString()) }}
@else
<i class="fa-solid fa-clock-slash" style="color: var(--text-muted, #888);"></i> Never
@endif
</span>
@if(can_manage_item)
<div class="info-expiry-edit-controls" style="display: inline-flex; align-items: center; gap: 6px;">
<select id="info-expiry-select" class="info-expiry-select" style="padding: 2px 6px; font-size: 0.85em; background: rgba(0,0,0,0.4); color: #fff; border: 1px solid rgba(255,255,255,0.2); border-radius: 4px;" data-item-id="{{ item.id }}">
<option value="permanent" {{ !item.expires_at ? 'selected' : '' }}>Permanent (Never)</option>
<option value="30minutes">30 Minutes</option>
<option value="1hour">1 Hour</option>
<option value="24hours">24 Hours</option>
<option value="1week">1 Week</option>
<option value="1month">1 Month</option>
</select>
<button id="info-set-expiry-btn" class="btn-secondary btn-sm" style="padding: 2px 8px; font-size: 0.8em;" data-item-id="{{ item.id }}"><i class="fa-solid fa-check"></i> Save</button>
</div>
@endif
</div>
</td>
</tr>
@endif
@include(snippets/info-modal)
<tr>
<th>{{ t('info_modal.file_size') || 'File Size' }}</th>
<td>{{ item.size }}</td>
</tr>
@if(item_has_dimensions)
<tr>
<th>{{ t('info_modal.dimensions') || 'Dimensions' }}</th>
<td>{{ item.width }} × {{ item.height }}</td>
</tr>
@endif
<tr>
<th>{{ t('info_modal.mime_type') || 'MIME Type' }}</th>
<td><code>{{ item.mime }}</code></td>
</tr>
@if(item.checksum)
<tr>
<th>{{ t('info_modal.sha256') || 'SHA-256 Hash' }}</th>
<td><pre class="info-hash-codeblock"><code style="word-break: break-all;">{{ item.checksum.split('_bypass_')[0] }}</code></pre></td>
</tr>
@endif
@if(item.show_repost_row)
<tr class="info-repost-row">
<th>Repost</th>
<td>
@each(item.reposts as rp)
@if(rp.match_type === 'phash')
<a href="/{{ rp.slug || rp.id }}" style="margin-right: 4px; opacity: 0.75;" tooltip="Visually similar (perceptual hash)" flow="up">~#{{ rp.slug || rp.id }}</a>
@else
<a href="/{{ rp.slug || rp.id }}" style="margin-right: 4px;" tooltip="Exact duplicate (checksum)" flow="up">#{{ rp.slug || rp.id }}</a>
@endif
@endeach
</td>
</tr>
@endif
<tr>
<th>{{ t('info_modal.direct_url') || 'Direct URL' }}</th>
<td>
<a href="{{ item.mime === 'video/youtube' ? 'https://www.youtube.com/watch?v=' + item.dest.replace('yt:', '') : item.dest }}" target="_blank">
{{ t('info_modal.view_file') || 'View File' }}
</a>
</td>
</tr>
@if(item.src.short)
<tr>
<th>{{ t('info_modal.source') || 'Source' }}</th>
<td><a href="{{ item.src.long }}" target="_blank" style="word-break: break-all;">{{ item.src.short }}</a></td>
</tr>
@endif
</table>
</div>
<div class="modal-actions" style="display: flex; justify-content: flex-end; gap: 10px;">
@if(can_manage_item)
<button class="btn-secondary" id="info-rethumb-btn" data-item-id="{{ item.id }}"><i class="fa-solid fa-arrows-rotate"></i> Regenerate Thumbnail</button>
@endif
<button class="btn-secondary" id="info-modal-close">{{ t('common.close') || 'Close' }}</button>
</div>
</div>
</div>
<div id="visibility-modal" class="modal-overlay" style="display: none;">
<div class="modal-content" style="max-width: 420px;">
<div class="modal-header" style="margin-bottom: 15px; border-bottom: 1px solid var(--border-color, #333); padding-bottom: 10px;">

View File

@@ -0,0 +1,188 @@
<div id="info-modal" class="modal-overlay" style="display: none;">
<div class="modal-content infobox-modal-content">
<!-- Header -->
<div class="infobox-modal-header">
<div class="infobox-header-title">
<div class="infobox-icon-badge">
<i class="fa-solid fa-circle-info"></i>
</div>
<div class="infobox-header-text">
<h3>{{ t('info_modal.title') || 'Post & File Details' }}</h3>
<span class="infobox-sub-heading">ID: <code>{{ item.id }}</code></span>
</div>
</div>
<button type="button" class="infobox-close-icon-btn" id="info-modal-close-icon" title="{{ t('common.close') || 'Close' }}">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
<!-- Body -->
<div class="infobox-modal-body">
<!-- Section 1: Post Details -->
<div class="infobox-section">
<div class="infobox-section-header">
<i class="fa-solid fa-sliders"></i>
<span>Post Configuration</span>
</div>
<div class="infobox-cards-grid">
@if(enable_item_title)
<div class="infobox-card full-width">
<label class="infobox-card-label"><i class="fa-solid fa-heading"></i> Title</label>
@if(can_manage_item)
<div class="info-title-edit-wrap">
<input type="text" id="info-title-input" class="info-title-input" value="{!! item.title || '' !!}" placeholder="Add a title…" maxlength="500" data-item-id="{{ item.id }}" />
<button type="button" id="info-title-save" class="info-title-save-btn" title="Save Title"><i class="fa-solid fa-check"></i></button>
</div>
<span id="info-title-status" class="info-title-status" style="display:none"></span>
@else
<div class="infobox-card-value">{!! item.title || '<span class="text-muted">No title set</span>' !!}</div>
@endif
</div>
@endif
<div class="infobox-card">
<label class="infobox-card-label"><i class="fa-solid fa-eye"></i> Visibility</label>
<div class="infobox-card-value-row">
<span id="info-visibility-label" class="visibility-badge vis-{{ item.visibility || 0 }}">
@if(item.visibility === 2)
<i class="fa-solid fa-lock" style="color: var(--color-danger, #ff4444);"></i> Private
@elseif(item.visibility === 1)
<i class="fa-solid fa-link" style="color: var(--color-warning, #ffbb33);"></i> Unlisted
@else
<i class="fa-solid fa-globe" style="color: var(--color-success, #00C851);"></i> Public
@endif
</span>
@if(can_manage_item)
<button type="button" id="info-visibility-edit-btn" class="infobox-action-btn" data-item-id="{{ item.id }}" data-visibility="{{ item.visibility || 0 }}">
<i class="fa-solid fa-pen"></i> Edit
</button>
@endif
</div>
</div>
@if(enable_expiring_uploads !== false)
<div class="infobox-card">
<label class="infobox-card-label"><i class="fa-solid fa-hourglass-half"></i> Expiration</label>
<div class="infobox-expiry-content">
<span id="info-expiry-label" class="expiry-status-label" title="{{ item.expires_at ? new Date(item.expires_at * 1000).toLocaleString() : '' }}">
@if(item.expires_at)
<i class="fa-solid fa-clock" style="color: #ffaa00;"></i> {{ item.expires_in || ('in ' + new Date(item.expires_at * 1000).toLocaleString()) }}
@else
<i class="fa-solid fa-clock-slash" style="color: var(--text-muted, #888);"></i> Permanent
@endif
</span>
@if(can_manage_item)
<div class="info-expiry-edit-controls">
<select id="info-expiry-select" class="infobox-select" data-item-id="{{ item.id }}">
<option value="permanent" {{ !item.expires_at ? 'selected' : '' }}>Permanent</option>
<option value="30minutes">30 Minutes</option>
<option value="1hour">1 Hour</option>
<option value="24hours">24 Hours</option>
<option value="1week">1 Week</option>
<option value="1month">1 Month</option>
</select>
<button type="button" id="info-set-expiry-btn" class="infobox-action-btn" data-item-id="{{ item.id }}" title="Save Expiration">
<i class="fa-solid fa-check"></i>
</button>
</div>
@endif
</div>
</div>
@endif
</div>
</div>
<!-- Section 2: Technical File Specifications -->
<div class="infobox-section">
<div class="infobox-section-header">
<i class="fa-solid fa-file-code"></i>
<span>Technical Specifications</span>
</div>
<div class="infobox-cards-grid">
<div class="infobox-card">
<label class="infobox-card-label"><i class="fa-solid fa-hard-drive"></i> File Size</label>
<div class="infobox-card-value font-mono">{{ item.size }}</div>
</div>
@if(item_has_dimensions)
<div class="infobox-card">
<label class="infobox-card-label"><i class="fa-solid fa-ruler-combined"></i> Dimensions</label>
<div class="infobox-card-value font-mono">{{ item.width }} × {{ item.height }} px</div>
</div>
@endif
<div class="infobox-card">
<label class="infobox-card-label"><i class="fa-solid fa-file-lines"></i> MIME Type</label>
<div class="infobox-card-value"><code class="mime-pill">{{ item.mime }}</code></div>
</div>
<div class="infobox-card">
<label class="infobox-card-label"><i class="fa-solid fa-arrow-up-right-from-square"></i> Direct Link</label>
<div class="infobox-card-value">
<a href="{{ item.mime === 'video/youtube' ? 'https://www.youtube.com/watch?v=' + item.dest.replace('yt:', '') : item.dest }}" target="_blank" class="infobox-link-pill">
<i class="fa-solid fa-up-right-from-square"></i> {{ t('info_modal.view_file') || 'Open File' }}
</a>
</div>
</div>
@if(item.src && item.src.short)
<div class="infobox-card full-width">
<label class="infobox-card-label"><i class="fa-solid fa-link"></i> Source URL</label>
<div class="infobox-card-value">
<a href="{{ item.src.long }}" target="_blank" class="infobox-source-link">
<i class="fa-solid fa-globe"></i> {{ item.src.short }}
</a>
</div>
</div>
@endif
@if(item.checksum)
<div class="infobox-card full-width">
<div class="infobox-card-label-row">
<label class="infobox-card-label"><i class="fa-solid fa-fingerprint"></i> SHA-256 Hash</label>
<button type="button" class="copy-hash-btn" id="info-copy-hash-btn" data-hash="{{ item.checksum.split('_bypass_')[0] }}" title="Copy SHA-256 Hash">
<i class="fa-solid fa-copy"></i> Copy
</button>
</div>
<div class="info-hash-codeblock font-mono">
<code>{{ item.checksum.split('_bypass_')[0] }}</code>
</div>
</div>
@endif
</div>
</div>
<!-- Section 3: Reposts & Duplicates (if present) -->
@if(item.show_repost_row)
<div class="infobox-section">
<div class="infobox-section-header">
<i class="fa-solid fa-copy"></i>
<span>Similar & Duplicate Uploads</span>
</div>
<div class="infobox-reposts-list">
@each(item.reposts as rp)
<a href="/{{ rp.slug || rp.id }}" class="repost-pill {{ rp.match_type === 'phash' ? 'phash' : 'exact' }}" tooltip="{{ rp.match_type === 'phash' ? 'Visually similar (perceptual hash)' : 'Exact duplicate (checksum)' }}" flow="up">
<i class="fa-solid {{ rp.match_type === 'phash' ? 'fa-clone' : 'fa-copy' }}"></i>
<span>{{ rp.match_type === 'phash' ? '~#' : '#' }}{{ rp.slug || rp.id }}</span>
</a>
@endeach
</div>
</div>
@endif
</div>
<!-- Footer -->
<div class="infobox-modal-footer">
@if(can_manage_item)
<button type="button" class="btn-infobox-action" id="info-rethumb-btn" data-item-id="{{ item.id }}">
<i class="fa-solid fa-arrows-rotate"></i> Regenerate Thumbnail
</button>
@endif
<button type="button" class="btn-infobox-close" id="info-modal-close">{{ t('common.close') || 'Close' }}</button>
</div>
</div>
</div>