classify admin

This commit is contained in:
Husanjonazamov
2026-02-24 12:52:01 +05:00
commit e0f1989655
769 changed files with 1263008 additions and 0 deletions

View File

@@ -0,0 +1,468 @@
@extends('layouts.main')
@section('title')
{{ __('Watermark Settings') }}
@endsection
@section('page-title')
<div class="page-title">
<div class="row">
<div class="col-12 col-md-6 order-md-1 order-last">
<h4>{{ __('Watermark Settings') }}</h4>
</div>
</div>
</div>
@endsection
@section('content')
<section class="section">
{!! Form::open(['route' => 'settings.watermark-settings-store', 'data-parsley-validate', 'class' => 'create-form', 'data-success-function'=> "formSuccessFunction", 'enctype' => 'multipart/form-data']) !!}
{{ csrf_field() }}
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-body">
<div class="divider pt-3">
<h6 class="divider-text">{{ __('Watermark Configuration') }}</h6>
</div>
{{-- Enable/Disable Watermark --}}
<div class="form-group mt-3">
<label class="form-label" for="watermark_enabled">{{ __('Enable Watermark') }}</label>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="watermark_enabled" id="watermark_enabled" value="1"
{{ ($watermarkSettings['enabled'] ?? 0) == 1 ? 'checked' : '' }}
onchange="toggleWatermarkSettings(); updateEnabledLabel();">
<input type="hidden" name="watermark_enabled" value="0" id="watermark_enabled_hidden">
<label class="form-check-label" for="watermark_enabled" id="enabled-label">
{{ ($watermarkSettings['enabled'] ?? 0) == 1 ? __('Enabled') : __('Disabled') }}
</label>
</div>
<small class="text-muted">{{ __('When enabled, watermarks will be applied to uploaded images') }}</small>
</div>
{{-- Watermark Image Upload --}}
<div class="form-group mt-3" id="watermark-image-group">
<label class="form-label" for="watermark_image">{{ __('Watermark Image') }}</label>
<input type="file" name="watermark_image" id="watermark_image" class="form-control"
accept="image/png,image/jpeg,image/jpg"
onchange="previewWatermarkImage(this); updatePreview();">
<small class="text-muted">{{ __('Upload a custom watermark image (PNG, JPG, JPEG). If not uploaded, default logo will be used.') }}</small>
@if(!empty($watermarkSettings['watermark_image_url']))
<div class="mt-2">
<p class="text-success mb-1"><small>{{ __('Current Watermark:') }}</small></p>
<img src="{{ $watermarkSettings['watermark_image_url'] }}"
alt="Current Watermark"
style="max-width: 150px; max-height: 150px; border: 1px solid #ddd; padding: 5px; border-radius: 4px;"
id="current-watermark-preview">
</div>
@else
<div class="mt-2">
<p class="text-info mb-1"><small>{{ __('Using default logo: Company Logo') }}</small></p>
</div>
@endif
<div id="new-watermark-preview" class="mt-2" style="display: none;">
<p class="text-success mb-1"><small>{{ __('New Watermark Preview:') }}</small></p>
<img id="new-watermark-preview-img" src="" alt="New Watermark"
style="max-width: 150px; max-height: 150px; border: 1px solid #ddd; padding: 5px; border-radius: 4px;">
</div>
</div>
{{-- Opacity --}}
<div class="form-group mt-3" id="watermark-settings-group">
<label class="form-label" for="opacity">{{ __('Opacity') }} (<span id="opacity-value">{{ $watermarkSettings['opacity'] ?? 25 }}</span>%)</label>
<input type="range" name="opacity" id="opacity" class="form-range" min="0" max="100"
value="{{ $watermarkSettings['opacity'] ?? 25 }}"
data-parsley-required="true"
oninput="updatePreview(); document.getElementById('opacity-value').textContent = this.value;">
<div class="d-flex justify-content-between">
<small>0%</small>
<small>100%</small>
</div>
</div>
{{-- Size --}}
<div class="form-group mt-3">
<label class="form-label" for="size">{{ __('Size') }} (<span id="size-value">{{ $watermarkSettings['size'] ?? 10 }}</span>%)</label>
<input type="range" name="size" id="size" class="form-range" min="1" max="100"
value="{{ $watermarkSettings['size'] ?? 10 }}"
data-parsley-required="true"
oninput="updatePreview(); document.getElementById('size-value').textContent = this.value;">
<div class="d-flex justify-content-between">
<small>1%</small>
<small>100%</small>
</div>
</div>
{{-- Style --}}
<div class="form-group mt-3">
<label class="form-label" for="style">{{ __('Style') }}</label>
<select name="style" id="style" class="form-select" data-parsley-required="true" onchange="updatePreview(); togglePositionField();">
<option value="tile" {{ ($watermarkSettings['style'] ?? 'tile') == 'tile' ? 'selected' : '' }}>{{ __('Tile (Repeat Pattern)') }}</option>
<option value="single" {{ ($watermarkSettings['style'] ?? 'tile') == 'single' ? 'selected' : '' }}>{{ __('Single Watermark') }}</option>
<option value="center" {{ ($watermarkSettings['style'] ?? 'tile') == 'center' ? 'selected' : '' }}>{{ __('Center Only') }}</option>
</select>
</div>
{{-- Position --}}
<div class="form-group mt-3" id="position-group">
<label class="form-label" for="position">{{ __('Position') }}</label>
<select name="position" id="position" class="form-select" data-parsley-required="false" onchange="updatePreview();">
<option value="top-left" {{ ($watermarkSettings['position'] ?? 'center') == 'top-left' ? 'selected' : '' }}>{{ __('Top Left') }}</option>
<option value="top-right" {{ ($watermarkSettings['position'] ?? 'center') == 'top-right' ? 'selected' : '' }}>{{ __('Top Right') }}</option>
<option value="bottom-left" {{ ($watermarkSettings['position'] ?? 'center') == 'bottom-left' ? 'selected' : '' }}>{{ __('Bottom Left') }}</option>
<option value="bottom-right" {{ ($watermarkSettings['position'] ?? 'center') == 'bottom-right' ? 'selected' : '' }}>{{ __('Bottom Right') }}</option>
<option value="center" {{ ($watermarkSettings['position'] ?? 'center') == 'center' ? 'selected' : '' }}>{{ __('Center') }}</option>
</select>
<small class="text-muted" id="position-note" style="display: none;">{{ __('Position is automatically set to center for this style') }}</small>
{{-- Hidden input for position when style is 'tile' --}}
<input type="hidden" name="position_hidden" id="position_hidden" value="center">
</div>
{{-- Rotation --}}
<div class="form-group mt-3">
<label class="form-label" for="rotation">{{ __('Rotation') }} (<span id="rotation-value">{{ $watermarkSettings['rotation'] ?? -30 }}</span>°)</label>
<input type="range" name="rotation" id="rotation" class="form-range" min="-360" max="360"
value="{{ $watermarkSettings['rotation'] ?? -30 }}"
oninput="updatePreview(); document.getElementById('rotation-value').textContent = this.value;">
<div class="d-flex justify-content-between">
<small>-360°</small>
<small>360°</small>
</div>
</div>
<div class="col-12 d-flex justify-content-end mt-4">
<button type="submit" class="btn btn-primary me-1 mb-1">{{ __('Save Settings') }}</button>
</div>
</div>
</div>
</div>
{{-- Preview Section --}}
<div class="col-md-6">
<div class="card">
<div class="card-body">
<div class="divider pt-3">
<h6 class="divider-text">{{ __('Preview') }}</h6>
</div>
<div class="form-group mt-3">
<div id="preview-container" style="position: relative; width: 100%; height: 400px; border: 2px solid #ffffff; border-radius: 8px; overflow: hidden; background: linear-gradient(45deg, #f0f0f0 25%, transparent 25%), linear-gradient(-45deg, #f0f0f0 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #f0f0f0 75%), linear-gradient(-45deg, transparent 75%, #f0f0f0 75%); background-size: 20px 20px; background-position: 0 0, 0 10px, 10px -10px, -10px 0px;">
<div id="preview-image" style="width: 100%; height: 100%; background: linear-gradient(135deg, #eaebef 0%, #e1dfe4 100%); display: flex; align-items: center; justify-content: center; color: white; font-size: 24px; font-weight: bold;">
{{ __('Sample Image') }}
</div>
<div id="watermark-preview" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 10;"></div>
</div>
<p class="text-muted mt-2 text-center"><small>{{ __('This is a visual preview of how the watermark will appear') }}</small></p>
</div>
</div>
</div>
</div>
</div>
{{-- @dd($watermarkSettings); --}}
{!! Form::close() !!}
</section>
@endsection
@section('script')
<script>
const defaultWatermarkPath = "{{ asset('assets/images/logo/logo.png') }}";
const customWatermarkPath = @if(!empty($watermarkSettings['watermark_image_url'])) "{{ $watermarkSettings['watermark_image_url'] }}" @else null @endif;
let currentWatermarkPath = customWatermarkPath || defaultWatermarkPath;
function previewWatermarkImage(input) {
if (input.files && input.files[0]) {
const reader = new FileReader();
reader.onload = function(e) {
const previewDiv = document.getElementById('new-watermark-preview');
const previewImg = document.getElementById('new-watermark-preview-img');
previewImg.src = e.target.result;
previewDiv.style.display = 'block';
currentWatermarkPath = e.target.result;
updatePreview();
};
reader.readAsDataURL(input.files[0]);
}
}
function updateEnabledLabel() {
const enabled = document.getElementById('watermark_enabled').checked;
const label = document.getElementById('enabled-label');
label.textContent = enabled ? '{{ __('Enabled') }}' : '{{ __('Disabled') }}';
}
function updateEnabledLabel() {
const enabled = document.getElementById('watermark_enabled').checked;
const label = document.getElementById('enabled-label');
if (label) {
label.textContent = enabled ? '{{ __('Enabled') }}' : '{{ __('Disabled') }}';
}
}
function togglePositionField() {
const style = document.getElementById('style').value;
const positionSelect = document.getElementById('position');
const positionGroup = document.getElementById('position-group');
const positionNote = document.getElementById('position-note');
if (style === 'tile') {
// Requirement: Hide when Tile is selected
positionGroup.style.display = 'none';
} else if (style === 'center') {
// Requirement: Show but Disable when Center Only is selected
positionGroup.style.display = 'block';
positionSelect.value = 'center'; // Force the value to center
positionSelect.disabled = true;
positionSelect.style.opacity = '0.6';
positionNote.style.display = 'block';
} else {
// Default: Single Watermark
positionGroup.style.display = 'block';
positionSelect.disabled = false;
positionSelect.style.opacity = '1';
positionNote.style.display = 'none';
}
}
function toggleWatermarkSettings() {
const enabled = document.getElementById('watermark_enabled').checked;
const settingsGroup = document.getElementById('watermark-settings-group');
const imageGroup = document.getElementById('watermark-image-group');
const positionGroup = document.getElementById('position-group');
const styleSelect = document.getElementById('style');
const opacityInput = document.getElementById('opacity');
const sizeInput = document.getElementById('size');
const rotationInput = document.getElementById('rotation');
const positionSelect = document.getElementById('position');
if (enabled) {
document.getElementById('watermark_enabled_hidden').value = '1';
settingsGroup.style.opacity = '1';
imageGroup.style.opacity = '1';
styleSelect.disabled = false;
opacityInput.disabled = false;
sizeInput.disabled = false;
rotationInput.disabled = false;
// Let togglePositionField handle the position logic
togglePositionField();
} else {
document.getElementById('watermark_enabled_hidden').value = '0';
settingsGroup.style.opacity = '0.5';
imageGroup.style.opacity = '0.5';
styleSelect.disabled = true;
opacityInput.disabled = true;
sizeInput.disabled = true;
rotationInput.disabled = true;
positionSelect.disabled = true;
}
updatePreview();
}
function createWatermarkElement(size, opacity, rotation) {
const watermark = document.createElement('img');
watermark.src = currentWatermarkPath;
watermark.style.opacity = opacity / 100;
watermark.style.transform = `rotate(${rotation}deg)`;
watermark.style.width = size + 'px';
watermark.style.height = 'auto';
watermark.style.imageRendering = 'auto';
watermark.style.maxWidth = size + 'px';
watermark.style.maxHeight = size + 'px';
watermark.onerror = function() {
// If logo doesn't exist, create a placeholder
const placeholder = document.createElement('div');
placeholder.style.width = size + 'px';
placeholder.style.height = size + 'px';
placeholder.style.border = '2px dashed #999';
placeholder.style.display = 'flex';
placeholder.style.alignItems = 'center';
placeholder.style.justifyContent = 'center';
placeholder.style.opacity = opacity / 100;
placeholder.style.transform = `rotate(${rotation}deg)`;
placeholder.textContent = 'LOGO';
placeholder.style.fontSize = Math.max(12, size / 4) + 'px';
placeholder.style.color = '#999';
placeholder.style.backgroundColor = 'rgba(255, 255, 255, 0.8)';
placeholder.style.borderRadius = '4px';
this.parentNode.replaceChild(placeholder, this);
};
watermark.onload = function() {
// Ensure image maintains aspect ratio
if (this.naturalWidth > 0 && this.naturalHeight > 0) {
const aspectRatio = this.naturalHeight / this.naturalWidth;
this.style.height = (size * aspectRatio) + 'px';
}
};
return watermark;
}
function updatePreview() {
const enabled = document.getElementById('watermark_enabled').checked;
const previewContainer = document.getElementById('preview-container');
const watermarkPreview = document.getElementById('watermark-preview');
// Clear previous watermark
watermarkPreview.innerHTML = '';
// If watermark is disabled, don't show preview
if (!enabled) {
return;
}
const opacity = parseInt(document.getElementById('opacity').value);
const size = parseInt(document.getElementById('size').value);
const style = document.getElementById('style').value;
const position = document.getElementById('position').value;
const rotation = parseInt(document.getElementById('rotation').value);
const containerWidth = previewContainer.offsetWidth;
const containerHeight = previewContainer.offsetHeight;
// Calculate watermark size
const watermarkSize = (containerWidth * size) / 100;
if (style === 'tile') {
// Create tiled pattern
const spacing = watermarkSize * 1.5;
const yPositions = [];
for (let y = 0; y < containerHeight; y += spacing) {
yPositions.push(y);
}
// Ensure last row is at the bottom - calculate bottom margin to maintain spacing
const lastY = yPositions[yPositions.length - 1];
const isLastRow = (y) => y === lastY;
// Calculate bottom margin to maintain similar spacing as top (10px from top)
const bottomMargin = 10;
for (let i = 0; i < yPositions.length; i++) {
const y = yPositions[i];
const isBottomRow = isLastRow(y);
for (let x = 0; x < containerWidth; x += spacing) {
const tile = createWatermarkElement(watermarkSize, opacity, rotation);
tile.style.position = 'absolute';
tile.style.left = x + 'px';
if (isBottomRow) {
// Use bottom positioning to stick to bottom
tile.style.bottom = bottomMargin + 'px';
tile.style.top = 'auto';
} else {
tile.style.top = y + 'px';
tile.style.bottom = 'auto';
}
watermarkPreview.appendChild(tile);
}
}
} else if (style === 'center') {
// Center only - always use center position
const watermark = createWatermarkElement(watermarkSize, opacity, rotation);
watermark.style.position = 'absolute';
const left = (containerWidth - watermarkSize) / 2;
const top = (containerHeight - watermarkSize) / 2;
watermark.style.left = left + 'px';
watermark.style.top = top + 'px';
watermarkPreview.appendChild(watermark);
} else if (style === 'single') {
// Single watermark - use position dropdown
const watermark = createWatermarkElement(watermarkSize, opacity, rotation);
watermark.style.position = 'absolute';
// Calculate position based on dropdown
let left = 0, top = 0, bottom = null;
switch(position) {
case 'top-left':
left = 10;
top = 10;
break;
case 'top-right':
left = containerWidth - watermarkSize - 10;
top = 10;
break;
case 'bottom-left':
left = 10;
bottom = 10;
break;
case 'bottom-right':
left = containerWidth - watermarkSize - 10;
bottom = 10;
break;
case 'center':
default:
left = (containerWidth - watermarkSize) / 2;
top = (containerHeight - watermarkSize) / 2;
break;
}
watermark.style.left = left + 'px';
if (bottom !== null) {
watermark.style.bottom = bottom + 'px';
watermark.style.top = 'auto';
} else {
watermark.style.top = top + 'px';
watermark.style.bottom = 'auto';
}
watermarkPreview.appendChild(watermark);
}
}
function togglePositionField() {
const style = document.getElementById('style').value;
const positionSelect = document.getElementById('position');
const positionGroup = document.getElementById('position-group');
const positionNote = document.getElementById('position-note');
const positionHidden = document.getElementById('position_hidden');
if (style === 'tile') {
// Hide position group when Tile is selected
positionGroup.style.display = 'none';
// Set hidden input value for form submission
if (positionHidden) {
positionHidden.value = 'center';
}
// Also set the select value (even though hidden)
positionSelect.value = 'center';
// Remove required attribute
positionSelect.removeAttribute('data-parsley-required');
} else if (style === 'center') {
// Show but disable when Center Only is selected
positionGroup.style.display = 'block';
positionSelect.value = 'center'; // Force the value to center
positionSelect.disabled = true;
positionSelect.style.opacity = '0.6';
positionNote.style.display = 'block';
// Set required for validation
positionSelect.setAttribute('data-parsley-required', 'true');
} else {
// Default: Single Watermark - show and enable
positionGroup.style.display = 'block';
positionSelect.disabled = false;
positionSelect.style.opacity = '1';
positionNote.style.display = 'none';
// Set required for validation
positionSelect.setAttribute('data-parsley-required', 'true');
}
}
// Initialize preview on page load
document.addEventListener('DOMContentLoaded', function() {
// Wait for container to be fully rendered
setTimeout(function() {
toggleWatermarkSettings();
togglePositionField();
updatePreview();
}, 100);
// Update preview when window is resized
window.addEventListener('resize', function() {
setTimeout(updatePreview, 100);
});
});
function formSuccessFunction(response) {
if(!response.error && !response.warning){
setTimeout(() => {
window.location.reload();
}, 500);
}
}
</script>
@endsection