This commit is contained in:
parent
06a2fb398d
commit
1467e83ccf
326
assets/app.js
326
assets/app.js
|
|
@ -7,9 +7,327 @@ import './bootstrap.js';
|
|||
*/
|
||||
|
||||
// any CSS you import will output into a single css file (app.css in this case)
|
||||
import './styles/global.scss';
|
||||
import './styles/tailwind.css';
|
||||
import './styles/app.css';
|
||||
|
||||
// Import Bootstrap and make it globally available
|
||||
import * as bootstrap from 'bootstrap';
|
||||
window.bootstrap = bootstrap;
|
||||
// Notification System
|
||||
class NotificationSystem {
|
||||
constructor() {
|
||||
this.container = null;
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
// Create notification container if it doesn't exist
|
||||
this.container = document.getElementById('notification-container');
|
||||
if (!this.container) {
|
||||
this.container = document.createElement('div');
|
||||
this.container.id = 'notification-container';
|
||||
this.container.className = 'notification-container';
|
||||
document.body.appendChild(this.container);
|
||||
}
|
||||
}
|
||||
|
||||
show(message, type = 'info', title = '', duration = 5000) {
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `notification ${type}`;
|
||||
|
||||
const icon = this.getIcon(type);
|
||||
const closeIcon = this.getCloseIcon();
|
||||
|
||||
notification.innerHTML = `
|
||||
<div class="notification-icon">${icon}</div>
|
||||
<div class="notification-content">
|
||||
${title ? `<div class="notification-title">${title}</div>` : ''}
|
||||
<div class="notification-message">${message}</div>
|
||||
</div>
|
||||
<button class="notification-close" onclick="this.parentElement.remove()">${closeIcon}</button>
|
||||
<div class="notification-progress" style="width: 100%; animation: progress ${duration}ms linear forwards;"></div>
|
||||
`;
|
||||
|
||||
// Add progress bar animation
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
@keyframes progress {
|
||||
from { width: 100%; }
|
||||
to { width: 0%; }
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
this.container.appendChild(notification);
|
||||
|
||||
// Trigger animation
|
||||
setTimeout(() => {
|
||||
notification.classList.add('show');
|
||||
}, 10);
|
||||
|
||||
// Auto remove
|
||||
if (duration > 0) {
|
||||
setTimeout(() => {
|
||||
this.remove(notification);
|
||||
}, duration);
|
||||
}
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
getIcon(type) {
|
||||
const icons = {
|
||||
success: `<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>`,
|
||||
error: `<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>`,
|
||||
warning: `<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"></path>
|
||||
</svg>`,
|
||||
info: `<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>`
|
||||
};
|
||||
return icons[type] || icons.info;
|
||||
}
|
||||
|
||||
getCloseIcon() {
|
||||
return `<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>`;
|
||||
}
|
||||
|
||||
remove(notification) {
|
||||
if (notification && notification.parentElement) {
|
||||
notification.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
if (notification.parentElement) {
|
||||
notification.remove();
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
success(message, title = 'موفقیت') {
|
||||
return this.show(message, 'success', title);
|
||||
}
|
||||
|
||||
error(message, title = 'خطا') {
|
||||
return this.show(message, 'error', title);
|
||||
}
|
||||
|
||||
warning(message, title = 'هشدار') {
|
||||
return this.show(message, 'warning', title);
|
||||
}
|
||||
|
||||
info(message, title = 'اطلاعات') {
|
||||
return this.show(message, 'info', title);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize notification system
|
||||
const notification = new NotificationSystem();
|
||||
|
||||
// Make notification available globally
|
||||
window.notification = notification;
|
||||
|
||||
// Test notification system
|
||||
setTimeout(() => {
|
||||
if (window.notification) {
|
||||
console.log('Notification system initialized successfully');
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
// Blog functionality
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Blog search enhancement
|
||||
const searchInput = document.querySelector('input[name="search"]');
|
||||
if (searchInput) {
|
||||
searchInput.addEventListener('focus', function() {
|
||||
this.classList.add('blog-search-input');
|
||||
});
|
||||
|
||||
searchInput.addEventListener('blur', function() {
|
||||
this.classList.remove('blog-search-input');
|
||||
});
|
||||
}
|
||||
|
||||
// Blog card hover effects
|
||||
const blogCards = document.querySelectorAll('.group.bg-white.rounded-2xl');
|
||||
blogCards.forEach(card => {
|
||||
card.classList.add('blog-card-hover');
|
||||
});
|
||||
|
||||
// Pagination hover effects
|
||||
const paginationItems = document.querySelectorAll('nav a, nav span');
|
||||
paginationItems.forEach(item => {
|
||||
item.classList.add('pagination-item');
|
||||
});
|
||||
|
||||
// Smooth scroll for anchor links
|
||||
const anchorLinks = document.querySelectorAll('a[href^="#"]');
|
||||
anchorLinks.forEach(link => {
|
||||
link.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
const target = document.querySelector(this.getAttribute('href'));
|
||||
if (target) {
|
||||
target.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Lazy loading for images
|
||||
const images = document.querySelectorAll('img[data-src]');
|
||||
const imageObserver = new IntersectionObserver((entries, observer) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
const img = entry.target;
|
||||
img.src = img.dataset.src;
|
||||
img.classList.remove('blog-loading');
|
||||
img.classList.add('opacity-100');
|
||||
observer.unobserve(img);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
images.forEach(img => {
|
||||
img.classList.add('blog-loading', 'opacity-0');
|
||||
imageObserver.observe(img);
|
||||
});
|
||||
|
||||
// Reading progress bar for blog posts
|
||||
const blogPost = document.querySelector('main.min-h-screen.bg-gray-50');
|
||||
if (blogPost) {
|
||||
const progressBar = document.createElement('div');
|
||||
progressBar.className = 'fixed top-0 left-0 w-0 h-1 bg-gradient-to-r from-blue-500 to-purple-500 z-50 transition-all duration-300';
|
||||
document.body.appendChild(progressBar);
|
||||
|
||||
window.addEventListener('scroll', function() {
|
||||
const scrollTop = window.pageYOffset;
|
||||
const docHeight = document.body.scrollHeight - window.innerHeight;
|
||||
const scrollPercent = (scrollTop / docHeight) * 100;
|
||||
progressBar.style.width = scrollPercent + '%';
|
||||
});
|
||||
}
|
||||
|
||||
// Copy code blocks functionality
|
||||
const codeBlocks = document.querySelectorAll('pre code');
|
||||
codeBlocks.forEach(block => {
|
||||
const copyButton = document.createElement('button');
|
||||
copyButton.className = 'absolute top-2 left-2 px-2 py-1 text-xs bg-gray-800 text-white rounded opacity-0 group-hover:opacity-100 transition-opacity duration-200';
|
||||
copyButton.textContent = 'کپی';
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'relative group';
|
||||
wrapper.style.position = 'relative';
|
||||
|
||||
block.parentNode.insertBefore(wrapper, block);
|
||||
wrapper.appendChild(block);
|
||||
wrapper.appendChild(copyButton);
|
||||
|
||||
copyButton.addEventListener('click', function() {
|
||||
navigator.clipboard.writeText(block.textContent).then(() => {
|
||||
copyButton.textContent = 'کپی شد!';
|
||||
setTimeout(() => {
|
||||
copyButton.textContent = 'کپی';
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Q&A functionality
|
||||
// Add hover effects to Q&A cards
|
||||
const qaCards = document.querySelectorAll('.bg-white.rounded-2xl.shadow-soft');
|
||||
qaCards.forEach(card => {
|
||||
card.classList.add('qa-card-hover');
|
||||
});
|
||||
|
||||
// Add hover effects to Q&A tags
|
||||
const qaTags = document.querySelectorAll('.inline-flex.items-center.px-3.py-1');
|
||||
qaTags.forEach(tag => {
|
||||
tag.classList.add('qa-tag-hover');
|
||||
});
|
||||
|
||||
// Add focus effects to Q&A form inputs
|
||||
const qaInputs = document.querySelectorAll('input, textarea, select');
|
||||
qaInputs.forEach(input => {
|
||||
input.classList.add('qa-form-focus');
|
||||
});
|
||||
|
||||
// Add hover effects to Q&A pagination
|
||||
const qaPaginationItems = document.querySelectorAll('nav a, nav span');
|
||||
qaPaginationItems.forEach(item => {
|
||||
item.classList.add('qa-pagination-item');
|
||||
});
|
||||
|
||||
// Add stagger animation to Q&A cards
|
||||
qaCards.forEach((card, index) => {
|
||||
card.classList.add('qa-fade-in-up');
|
||||
if (index < 4) {
|
||||
card.classList.add(`qa-stagger-${index + 1}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Q&A search enhancement
|
||||
const qaSearchInput = document.querySelector('input[name="search"]');
|
||||
if (qaSearchInput) {
|
||||
qaSearchInput.addEventListener('focus', function() {
|
||||
this.parentElement.classList.add('ring-2', 'ring-blue-500');
|
||||
});
|
||||
|
||||
qaSearchInput.addEventListener('blur', function() {
|
||||
this.parentElement.classList.remove('ring-2', 'ring-blue-500');
|
||||
});
|
||||
}
|
||||
|
||||
// Q&A filter enhancement
|
||||
const qaFilterSelect = document.querySelector('select[name="filter"]');
|
||||
if (qaFilterSelect) {
|
||||
qaFilterSelect.addEventListener('change', function() {
|
||||
this.classList.add('bg-blue-50', 'border-blue-300');
|
||||
setTimeout(() => {
|
||||
this.classList.remove('bg-blue-50', 'border-blue-300');
|
||||
}, 300);
|
||||
});
|
||||
}
|
||||
|
||||
// Q&A vote button enhancement
|
||||
const qaVoteButtons = document.querySelectorAll('.vote-btn');
|
||||
qaVoteButtons.forEach(button => {
|
||||
button.classList.add('qa-vote-btn');
|
||||
});
|
||||
|
||||
// Q&A tag selection enhancement
|
||||
const qaTagSuggestions = document.querySelectorAll('.tag-suggestion');
|
||||
qaTagSuggestions.forEach(tag => {
|
||||
tag.addEventListener('click', function() {
|
||||
this.classList.toggle('qa-tag-selected');
|
||||
this.classList.toggle('qa-tag-unselected');
|
||||
});
|
||||
});
|
||||
|
||||
// Q&A answer acceptance enhancement
|
||||
const qaAcceptButtons = document.querySelectorAll('.accept-answer-btn');
|
||||
qaAcceptButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
this.classList.add('bg-green-200', 'text-green-800');
|
||||
setTimeout(() => {
|
||||
this.classList.remove('bg-green-200', 'text-green-800');
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
|
||||
// Q&A loading states
|
||||
const qaForms = document.querySelectorAll('form');
|
||||
qaForms.forEach(form => {
|
||||
form.addEventListener('submit', function() {
|
||||
const submitButton = this.querySelector('button[type="submit"]');
|
||||
if (submitButton) {
|
||||
submitButton.classList.add('qa-loading-shimmer');
|
||||
submitButton.disabled = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/* Custom styles for Hesabix */
|
||||
body, .lead {
|
||||
font-family: "Yekan Bakh FaNum";
|
||||
font-family: "Yekan Bakh FaNum", "Tahoma", "Arial", sans-serif;
|
||||
font-feature-settings: "kern" on, "liga" on, "dlig" on;
|
||||
-moz-font-feature-settings: "kern" on, "liga" on, "dlig" on;
|
||||
-webkit-font-feature-settings: "kern" on, "liga" on, "dlig" on;
|
||||
|
|
@ -7,118 +8,679 @@ body, .lead {
|
|||
-o-font-feature-settings: "kern" on, "liga" on, "dlig" on;
|
||||
}
|
||||
|
||||
/* استایلهای منوی ناوبری */
|
||||
.navbar {
|
||||
padding: 0.8rem 0;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
position: relative;
|
||||
color: #495057;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
color: #1743bb;
|
||||
background-color: rgba(23, 67, 187, 0.05);
|
||||
}
|
||||
|
||||
.nav-link.active {
|
||||
color: #1743bb;
|
||||
background-color: rgba(23, 67, 187, 0.1);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 5px rgba(23, 67, 187, 0.2);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(23, 67, 187, 0.3);
|
||||
}
|
||||
|
||||
.transition-all {
|
||||
transition: all 0.3s ease;
|
||||
/* RTL Support */
|
||||
[dir="rtl"] {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Custom utility classes */
|
||||
.rul {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.accordion-button:after {
|
||||
margin-right: auto;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre {
|
||||
border-radius: 0.5rem;
|
||||
direction: ltr;
|
||||
background-color: #d6d6df;
|
||||
background-color: #f3f4f6;
|
||||
padding: 0.9rem 0.8rem;
|
||||
color: blue;
|
||||
color: #1f2937;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
|
||||
/* استایلهای RTL برای Modal */
|
||||
#walletModal {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
/* Trust seals animation */
|
||||
.trust-seal-loading {
|
||||
animation: pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
#walletModal .modal-content {
|
||||
font-family: 'Yekan Bakh FaNum', 'Tahoma', 'Arial', sans-serif;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
@keyframes pulse {
|
||||
0% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
#walletModal .modal-header {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
/* Trust seals content */
|
||||
.trust-seals-content img {
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
max-height: 50px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#walletModal .modal-title {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
font-family: 'Yekan Bakh FaNum', 'Tahoma', 'Arial', sans-serif;
|
||||
.trust-seals-content img:hover {
|
||||
opacity: 0.8;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* Q&A specific styles */
|
||||
.qa-card-hover {
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.qa-card-hover:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 20px 40px -12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
/* Tag System Styles */
|
||||
.tag-suggestion {
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tag-suggestion::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
transition: left 0.5s;
|
||||
}
|
||||
|
||||
.tag-suggestion:hover::before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.tag-suggestion:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.selected-tags {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.selected-tags:empty {
|
||||
border-color: #e5e7eb;
|
||||
}
|
||||
|
||||
.selected-tags:not(:empty) {
|
||||
border-color: #3b82f6;
|
||||
background-color: #f8fafc;
|
||||
}
|
||||
|
||||
.tag-remove {
|
||||
transition: all 0.2s ease;
|
||||
border-radius: 50%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tag-remove:hover {
|
||||
background-color: rgba(239, 68, 68, 0.1);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.tag-remove:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
/* Tag Input Styles */
|
||||
#tag-input:focus {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 25px -5px rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
#add-tag-btn {
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#add-tag-btn::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
transition: left 0.5s;
|
||||
}
|
||||
|
||||
#add-tag-btn:hover::before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
#add-tag-btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
|
||||
}
|
||||
|
||||
#add-tag-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Loading Spinner for Tags */
|
||||
.loading-spinner {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid #e5e7eb;
|
||||
border-top: 2px solid #3b82f6;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
/* Tag Count Animation */
|
||||
#tag-count {
|
||||
transition: all 0.3s ease;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Tag Suggestions Container */
|
||||
#tag-suggestions {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #cbd5e0 #f7fafc;
|
||||
}
|
||||
|
||||
#tag-suggestions::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
#tag-suggestions::-webkit-scrollbar-track {
|
||||
background: #f7fafc;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#tag-suggestions::-webkit-scrollbar-thumb {
|
||||
background: #cbd5e0;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#tag-suggestions::-webkit-scrollbar-thumb:hover {
|
||||
background: #a0aec0;
|
||||
}
|
||||
|
||||
/* Tag Selection Animation */
|
||||
.tag-suggestion.selected {
|
||||
animation: tagSelect 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes tagSelect {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Tag Validation States */
|
||||
.tag-container.valid {
|
||||
border-color: #10b981;
|
||||
background: linear-gradient(135deg, #f0fdf4 0%, #ecfdf5 100%);
|
||||
}
|
||||
|
||||
.tag-container.invalid {
|
||||
border-color: #ef4444;
|
||||
background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);
|
||||
}
|
||||
|
||||
/* Responsive Tag System */
|
||||
@media (max-width: 640px) {
|
||||
.selected-tags {
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.tag-suggestion {
|
||||
font-size: 0.875rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
}
|
||||
|
||||
#tag-input {
|
||||
font-size: 0.875rem;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
#add-tag-btn {
|
||||
padding: 0.75rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.qa-vote-btn {
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.qa-vote-btn:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.qa-vote-btn:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.qa-tag-hover {
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.qa-tag-hover:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.qa-form-focus {
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.qa-form-focus:focus {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 25px -5px rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
.qa-accepted-answer {
|
||||
background: linear-gradient(135deg, #f0fdf4 0%, #ecfdf5 100%);
|
||||
border-left: 4px solid #10b981;
|
||||
}
|
||||
|
||||
.qa-question-stats {
|
||||
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
|
||||
}
|
||||
|
||||
.qa-editor-toolbar {
|
||||
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.qa-editor-toolbar button {
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.qa-editor-toolbar button:hover {
|
||||
background-color: #e2e8f0;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.qa-editor-toolbar button:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.qa-tag-selected {
|
||||
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
|
||||
color: white;
|
||||
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
.qa-tag-unselected {
|
||||
background: white;
|
||||
color: #374151;
|
||||
border: 1px solid #d1d5db;
|
||||
}
|
||||
|
||||
.qa-tag-unselected:hover {
|
||||
background: #f3f4f6;
|
||||
border-color: #9ca3af;
|
||||
}
|
||||
|
||||
.qa-pagination-item {
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.qa-pagination-item:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.qa-loading-shimmer {
|
||||
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
|
||||
background-size: 200% 100%;
|
||||
animation: qa-shimmer 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes qa-shimmer {
|
||||
0% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 200% 0;
|
||||
}
|
||||
}
|
||||
|
||||
.qa-fade-in-up {
|
||||
animation: qa-fadeInUp 0.6s ease-out;
|
||||
}
|
||||
|
||||
@keyframes qa-fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.qa-stagger-1 { animation-delay: 0.1s; }
|
||||
.qa-stagger-2 { animation-delay: 0.2s; }
|
||||
.qa-stagger-3 { animation-delay: 0.3s; }
|
||||
.qa-stagger-4 { animation-delay: 0.4s; }
|
||||
|
||||
/* Notification System */
|
||||
.notification-container {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 9999;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.notification {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: 12px;
|
||||
padding: 16px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border-left: 4px solid;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.notification.show {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.notification.success {
|
||||
border-left-color: #10b981;
|
||||
background: linear-gradient(135deg, #f0fdf4 0%, #ecfdf5 100%);
|
||||
}
|
||||
|
||||
.notification.error {
|
||||
border-left-color: #ef4444;
|
||||
background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);
|
||||
}
|
||||
|
||||
.notification.warning {
|
||||
border-left-color: #f59e0b;
|
||||
background: linear-gradient(135deg, #fffbeb 0%, #fef3c7 100%);
|
||||
}
|
||||
|
||||
.notification.info {
|
||||
border-left-color: #3b82f6;
|
||||
background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
|
||||
}
|
||||
|
||||
.notification-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.notification-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.notification-title {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
margin-bottom: 4px;
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
#walletModal .btn-close {
|
||||
margin-left: 0;
|
||||
margin-right: auto;
|
||||
order: -1;
|
||||
.notification-message {
|
||||
font-size: 13px;
|
||||
color: #6b7280;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
#walletModal .modal-body {
|
||||
direction: rtl;
|
||||
.notification-close {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
color: #9ca3af;
|
||||
transition: all 0.2s ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.notification-close:hover {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.notification-progress {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 3px;
|
||||
background: currentColor;
|
||||
border-radius: 0 0 12px 12px;
|
||||
transition: width linear;
|
||||
}
|
||||
|
||||
/* Loading Spinner */
|
||||
.loading-spinner {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid #e5e7eb;
|
||||
border-top: 2px solid #3b82f6;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* Blog specific styles */
|
||||
.blog-card-hover {
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.blog-card-hover:hover {
|
||||
transform: translateY(-8px);
|
||||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
/* Improved prose styling for blog content */
|
||||
.prose {
|
||||
color: #374151;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6 {
|
||||
color: #1f2937;
|
||||
font-weight: 700;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.prose h1 {
|
||||
font-size: 2.25rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.prose h2 {
|
||||
font-size: 1.875rem;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.prose h3 {
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.prose p {
|
||||
margin-bottom: 1.5rem;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.prose ul, .prose ol {
|
||||
margin-bottom: 1.5rem;
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
|
||||
.prose li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.prose blockquote {
|
||||
border-right: 4px solid #3b82f6;
|
||||
background-color: #f8fafc;
|
||||
padding: 1.5rem;
|
||||
margin: 2rem 0;
|
||||
border-radius: 0.5rem;
|
||||
font-style: italic;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
.prose code {
|
||||
background-color: #f1f5f9;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.875rem;
|
||||
color: #e11d48;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.prose pre {
|
||||
background-color: #1f2937;
|
||||
color: #f9fafb;
|
||||
padding: 1.5rem;
|
||||
border-radius: 0.75rem;
|
||||
overflow-x: auto;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
.prose pre code {
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.prose img {
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
.prose a {
|
||||
color: #3b82f6;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.prose a:hover {
|
||||
color: #1d4ed8;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.prose table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 2rem 0;
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.prose th, .prose td {
|
||||
padding: 0.75rem 1rem;
|
||||
text-align: right;
|
||||
font-family: 'Yekan Bakh FaNum', 'Tahoma', 'Arial', sans-serif;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
#walletModal .modal-footer {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
border-top: 1px solid #dee2e6;
|
||||
.prose th {
|
||||
background-color: #f9fafb;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
#walletModal .modal-footer .btn {
|
||||
font-family: 'Yekan Bakh FaNum', 'Tahoma', 'Arial', sans-serif;
|
||||
direction: rtl;
|
||||
.prose tr:hover {
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
|
||||
#walletModal .alert {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
font-family: 'Yekan Bakh FaNum', 'Tahoma', 'Arial', sans-serif;
|
||||
/* Blog search improvements */
|
||||
.blog-search-input {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* استایلهای backdrop برای RTL */
|
||||
.modal-backdrop {
|
||||
direction: rtl;
|
||||
.blog-search-input:focus {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 25px -5px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
/* Pagination improvements */
|
||||
.pagination-item {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.pagination-item:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* Loading states */
|
||||
.blog-loading {
|
||||
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 200% 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive improvements */
|
||||
@media (max-width: 640px) {
|
||||
.prose {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.prose h1 {
|
||||
font-size: 1.875rem;
|
||||
}
|
||||
|
||||
.prose h2 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.prose h3 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark mode support (if needed in future) */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.prose {
|
||||
color: #d1d5db;
|
||||
}
|
||||
|
||||
.prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6 {
|
||||
color: #f9fafb;
|
||||
}
|
||||
|
||||
.prose blockquote {
|
||||
background-color: #374151;
|
||||
color: #d1d5db;
|
||||
}
|
||||
|
||||
.prose code {
|
||||
background-color: #374151;
|
||||
color: #fbbf24;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
// assets/styles/global.scss
|
||||
|
||||
// customize some Bootstrap variables
|
||||
$primary: #1743bb;
|
||||
$link-hover-decoration: none;
|
||||
$accordion-button-bg: rgb(248, 249, 250);
|
||||
$accordion-bg: rgb(248, 249, 250);
|
||||
$accordion-button-active-bg: rgb(248, 249, 250);
|
||||
$accordion-padding-y: 0.6rem;
|
||||
// the ~ allows you to reference things in node_modules
|
||||
@import "~bootstrap/scss/bootstrap";
|
||||
403
assets/styles/tailwind.css
Normal file
403
assets/styles/tailwind.css
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
@import "tailwindcss";
|
||||
|
||||
/* RTL Support */
|
||||
[dir="rtl"] {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Custom components */
|
||||
.btn-primary {
|
||||
background-color: #1743bb;
|
||||
color: white;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #0d47a1;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(23, 67, 187, 0.3);
|
||||
}
|
||||
|
||||
.btn-outline-primary {
|
||||
border: 1px solid #1743bb;
|
||||
color: #1743bb;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-outline-primary:hover {
|
||||
background-color: #1743bb;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: white;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 2px 15px -3px rgba(0, 0, 0, 0.07), 0 10px 20px -2px rgba(0, 0, 0, 0.04);
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
background-color: #f9fafb;
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 0.5rem;
|
||||
color: #6b7280;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
color: #1743bb;
|
||||
background-color: rgba(23, 67, 187, 0.05);
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin-top: 0.5rem;
|
||||
width: 12rem;
|
||||
background: white;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 4px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
border: 1px solid #e5e7eb;
|
||||
padding: 0.5rem 0;
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
display: block;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
color: #374151;
|
||||
transition: background-color 0.2s ease;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.dropdown-item:hover {
|
||||
background-color: #f3f4f6;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
width: 100%;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 0.5rem;
|
||||
outline: none;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
outline: none;
|
||||
ring: 2px;
|
||||
ring-color: #1743bb;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: #374151;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: #f0fdf4;
|
||||
border-color: #bbf7d0;
|
||||
color: #166534;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
background-color: #fef2f2;
|
||||
border-color: #fecaca;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
background-color: #fffbeb;
|
||||
border-color: #fed7aa;
|
||||
color: #92400e;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
background-color: #eff6ff;
|
||||
border-color: #bfdbfe;
|
||||
color: #1e40af;
|
||||
}
|
||||
|
||||
.spinner-border {
|
||||
display: inline-block;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border: 2px solid currentColor;
|
||||
border-right-color: transparent;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.spinner-border-sm {
|
||||
width: 0.75rem;
|
||||
height: 0.75rem;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.modal {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 50;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-backdrop {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: relative;
|
||||
background: white;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||
max-width: 32rem;
|
||||
margin: 5rem auto;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 1.5rem;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 0.75rem;
|
||||
padding: 1.5rem;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #9ca3af;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.btn-close:hover {
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.btn-close::before {
|
||||
content: "×";
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Custom utilities for RTL */
|
||||
.text-primary {
|
||||
color: #1743bb;
|
||||
}
|
||||
|
||||
.bg-primary {
|
||||
background-color: #1743bb;
|
||||
}
|
||||
|
||||
.border-primary {
|
||||
border-color: #1743bb;
|
||||
}
|
||||
|
||||
.hover\:bg-primary:hover {
|
||||
background-color: #1743bb;
|
||||
}
|
||||
|
||||
.hover\:text-primary:hover {
|
||||
color: #1743bb;
|
||||
}
|
||||
|
||||
.focus\:ring-primary:focus {
|
||||
--tw-ring-color: #1743bb;
|
||||
}
|
||||
|
||||
/* انیمیشنهای اضافی */
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInLeft {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInRight {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scaleIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* کلاسهای انیمیشن */
|
||||
.animate-fade-in-up {
|
||||
animation: fadeInUp 0.6s ease-out;
|
||||
}
|
||||
|
||||
.animate-fade-in-left {
|
||||
animation: fadeInLeft 0.6s ease-out;
|
||||
}
|
||||
|
||||
.animate-fade-in-right {
|
||||
animation: fadeInRight 0.6s ease-out;
|
||||
}
|
||||
|
||||
.animate-scale-in {
|
||||
animation: scaleIn 0.6s ease-out;
|
||||
}
|
||||
|
||||
/* بهبود خطبندی متن */
|
||||
.line-clamp-2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.line-clamp-3 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* بهبود hover effects */
|
||||
.hover-lift {
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.hover-lift:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
/* بهبود gradient text */
|
||||
.gradient-text {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
/* بهبود backdrop blur */
|
||||
.backdrop-blur-custom {
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
/* بهبود responsive spacing */
|
||||
@media (max-width: 640px) {
|
||||
.container {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* بهبود focus states */
|
||||
.focus-ring {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.focus-ring:focus {
|
||||
outline: none;
|
||||
ring: 2px;
|
||||
ring-color: #3b82f6;
|
||||
ring-offset: 2px;
|
||||
}
|
||||
|
||||
/* بهبود loading states */
|
||||
.loading-shimmer {
|
||||
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 200% 0;
|
||||
}
|
||||
}
|
||||
834
package-lock.json
generated
834
package-lock.json
generated
|
|
@ -10,25 +10,41 @@
|
|||
"@babel/preset-env": "^7.16.0",
|
||||
"@hotwired/stimulus": "^3.0.0",
|
||||
"@hotwired/turbo": "^7.1.1 || ^8.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@symfony/stimulus-bridge": "^3.2.0",
|
||||
"@symfony/ux-turbo": "file:vendor/symfony/ux-turbo/assets",
|
||||
"@symfony/webpack-encore": "^5.0.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"bootstrap": "^5.3.3",
|
||||
"@tailwindcss/forms": "^0.5.10",
|
||||
"@tailwindcss/postcss": "^4.1.13",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"core-js": "^3.38.0",
|
||||
"css-loader": "^7.1.2",
|
||||
"postcss": "^8.5.6",
|
||||
"postcss-loader": "^8.1.1",
|
||||
"regenerator-runtime": "^0.13.9",
|
||||
"sass": "^1.83.1",
|
||||
"sass-loader": "^16.0.4",
|
||||
"style-loader": "^4.0.0",
|
||||
"tailwindcss": "^4.1.13",
|
||||
"webpack": "^5.74.0",
|
||||
"webpack-cli": "^5.1.0",
|
||||
"webpack-dev-server": "^5.2.2",
|
||||
"webpack-notifier": "^1.15.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
||||
|
|
@ -1584,6 +1600,19 @@
|
|||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/fs-minipass": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
|
||||
"integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"minipass": "^7.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jest/schemas": {
|
||||
"version": "29.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
|
||||
|
|
@ -1706,6 +1735,17 @@
|
|||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/remapping": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
|
||||
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
|
|
@ -1738,9 +1778,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
|
|
@ -2211,17 +2251,6 @@
|
|||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@sinclair/typebox": {
|
||||
"version": "0.27.8",
|
||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
|
||||
|
|
@ -2432,6 +2461,345 @@
|
|||
"webpack": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/forms": {
|
||||
"version": "0.5.10",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.10.tgz",
|
||||
"integrity": "sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mini-svg-data-uri": "^1.2.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/node": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.13.tgz",
|
||||
"integrity": "sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/remapping": "^2.3.4",
|
||||
"enhanced-resolve": "^5.18.3",
|
||||
"jiti": "^2.5.1",
|
||||
"lightningcss": "1.30.1",
|
||||
"magic-string": "^0.30.18",
|
||||
"source-map-js": "^1.2.1",
|
||||
"tailwindcss": "4.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/node/node_modules/jiti": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz",
|
||||
"integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.13.tgz",
|
||||
"integrity": "sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.4",
|
||||
"tar": "^7.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tailwindcss/oxide-android-arm64": "4.1.13",
|
||||
"@tailwindcss/oxide-darwin-arm64": "4.1.13",
|
||||
"@tailwindcss/oxide-darwin-x64": "4.1.13",
|
||||
"@tailwindcss/oxide-freebsd-x64": "4.1.13",
|
||||
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.13",
|
||||
"@tailwindcss/oxide-linux-arm64-gnu": "4.1.13",
|
||||
"@tailwindcss/oxide-linux-arm64-musl": "4.1.13",
|
||||
"@tailwindcss/oxide-linux-x64-gnu": "4.1.13",
|
||||
"@tailwindcss/oxide-linux-x64-musl": "4.1.13",
|
||||
"@tailwindcss/oxide-wasm32-wasi": "4.1.13",
|
||||
"@tailwindcss/oxide-win32-arm64-msvc": "4.1.13",
|
||||
"@tailwindcss/oxide-win32-x64-msvc": "4.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-android-arm64": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.13.tgz",
|
||||
"integrity": "sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-darwin-arm64": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.13.tgz",
|
||||
"integrity": "sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-darwin-x64": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.13.tgz",
|
||||
"integrity": "sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-freebsd-x64": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.13.tgz",
|
||||
"integrity": "sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.13.tgz",
|
||||
"integrity": "sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.13.tgz",
|
||||
"integrity": "sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.13.tgz",
|
||||
"integrity": "sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.13.tgz",
|
||||
"integrity": "sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.13.tgz",
|
||||
"integrity": "sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.13.tgz",
|
||||
"integrity": "sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==",
|
||||
"bundleDependencies": [
|
||||
"@napi-rs/wasm-runtime",
|
||||
"@emnapi/core",
|
||||
"@emnapi/runtime",
|
||||
"@tybys/wasm-util",
|
||||
"@emnapi/wasi-threads",
|
||||
"tslib"
|
||||
],
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/core": "^1.4.5",
|
||||
"@emnapi/runtime": "^1.4.5",
|
||||
"@emnapi/wasi-threads": "^1.0.4",
|
||||
"@napi-rs/wasm-runtime": "^0.2.12",
|
||||
"@tybys/wasm-util": "^0.10.0",
|
||||
"tslib": "^2.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.13.tgz",
|
||||
"integrity": "sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.13.tgz",
|
||||
"integrity": "sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/oxide/node_modules/detect-libc": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
|
||||
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/postcss": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.13.tgz",
|
||||
"integrity": "sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
"@tailwindcss/node": "4.1.13",
|
||||
"@tailwindcss/oxide": "4.1.13",
|
||||
"postcss": "^8.4.41",
|
||||
"tailwindcss": "4.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/typography": {
|
||||
"version": "0.5.16",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz",
|
||||
"integrity": "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lodash.castarray": "^4.4.0",
|
||||
"lodash.isplainobject": "^4.0.6",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"postcss-selector-parser": "6.0.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": {
|
||||
"version": "6.0.10",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
|
||||
"integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@trysound/sax": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
|
||||
|
|
@ -3122,9 +3490,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.4.20",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
|
||||
"integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==",
|
||||
"version": "10.4.21",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
|
||||
"integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -3142,11 +3510,11 @@
|
|||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.23.3",
|
||||
"caniuse-lite": "^1.0.30001646",
|
||||
"browserslist": "^4.24.4",
|
||||
"caniuse-lite": "^1.0.30001702",
|
||||
"fraction.js": "^4.3.7",
|
||||
"normalize-range": "^0.1.2",
|
||||
"picocolors": "^1.0.1",
|
||||
"picocolors": "^1.1.1",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
"bin": {
|
||||
|
|
@ -3366,26 +3734,6 @@
|
|||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/bootstrap": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
|
||||
"integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/twbs"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/bootstrap"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@popperjs/core": "^2.11.8"
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
|
|
@ -3520,9 +3868,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001690",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz",
|
||||
"integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==",
|
||||
"version": "1.0.30001741",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001741.tgz",
|
||||
"integrity": "sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -3571,6 +3919,16 @@
|
|||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/chownr": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
|
||||
"integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/chrome-trace-event": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
|
||||
|
|
@ -4429,9 +4787,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.18.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz",
|
||||
"integrity": "sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==",
|
||||
"version": "5.18.3",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
|
||||
"integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
|
@ -5869,6 +6227,255 @@
|
|||
"shell-quote": "^1.8.3"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss": {
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
|
||||
"integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==",
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"lightningcss-darwin-arm64": "1.30.1",
|
||||
"lightningcss-darwin-x64": "1.30.1",
|
||||
"lightningcss-freebsd-x64": "1.30.1",
|
||||
"lightningcss-linux-arm-gnueabihf": "1.30.1",
|
||||
"lightningcss-linux-arm64-gnu": "1.30.1",
|
||||
"lightningcss-linux-arm64-musl": "1.30.1",
|
||||
"lightningcss-linux-x64-gnu": "1.30.1",
|
||||
"lightningcss-linux-x64-musl": "1.30.1",
|
||||
"lightningcss-win32-arm64-msvc": "1.30.1",
|
||||
"lightningcss-win32-x64-msvc": "1.30.1"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-darwin-arm64": {
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz",
|
||||
"integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-darwin-x64": {
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz",
|
||||
"integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-freebsd-x64": {
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz",
|
||||
"integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm-gnueabihf": {
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz",
|
||||
"integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm64-gnu": {
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz",
|
||||
"integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm64-musl": {
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz",
|
||||
"integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-x64-gnu": {
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz",
|
||||
"integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-x64-musl": {
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz",
|
||||
"integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-win32-arm64-msvc": {
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz",
|
||||
"integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-win32-x64-msvc": {
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz",
|
||||
"integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss/node_modules/detect-libc": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
|
||||
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/lilconfig": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
|
||||
|
|
@ -5937,6 +6544,13 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.castarray": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
|
||||
"integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.debounce": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||
|
|
@ -5944,6 +6558,13 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.memoize": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
||||
|
|
@ -5951,6 +6572,13 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.uniq": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
|
||||
|
|
@ -5968,6 +6596,16 @@
|
|||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.18",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz",
|
||||
"integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
|
|
@ -6172,6 +6810,16 @@
|
|||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/mini-svg-data-uri": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
|
||||
"integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mini-svg-data-uri": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/minimalistic-assert": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||
|
|
@ -6179,6 +6827,45 @@
|
|||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/minipass": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/minizlib": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
|
||||
"integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minipass": "^7.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
|
||||
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mkdirp": "dist/cjs/src/bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
|
|
@ -6201,9 +6888,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
||||
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -6557,9 +7244,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.49",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
|
||||
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -6577,7 +7264,7 @@
|
|||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.7",
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
|
|
@ -8320,6 +9007,13 @@
|
|||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz",
|
||||
"integrity": "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
|
||||
|
|
@ -8330,6 +9024,34 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "7.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
|
||||
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@isaacs/fs-minipass": "^4.0.0",
|
||||
"chownr": "^3.0.0",
|
||||
"minipass": "^7.1.2",
|
||||
"minizlib": "^3.0.1",
|
||||
"mkdirp": "^3.0.1",
|
||||
"yallist": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tar/node_modules/yallist": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
|
||||
"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.37.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz",
|
||||
|
|
|
|||
|
|
@ -4,19 +4,22 @@
|
|||
"@babel/preset-env": "^7.16.0",
|
||||
"@hotwired/stimulus": "^3.0.0",
|
||||
"@hotwired/turbo": "^7.1.1 || ^8.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@symfony/stimulus-bridge": "^3.2.0",
|
||||
"@symfony/ux-turbo": "file:vendor/symfony/ux-turbo/assets",
|
||||
"@symfony/webpack-encore": "^5.0.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"bootstrap": "^5.3.3",
|
||||
"@tailwindcss/forms": "^0.5.10",
|
||||
"@tailwindcss/postcss": "^4.1.13",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"core-js": "^3.38.0",
|
||||
"css-loader": "^7.1.2",
|
||||
"postcss": "^8.5.6",
|
||||
"postcss-loader": "^8.1.1",
|
||||
"regenerator-runtime": "^0.13.9",
|
||||
"sass": "^1.83.1",
|
||||
"sass-loader": "^16.0.4",
|
||||
"style-loader": "^4.0.0",
|
||||
"tailwindcss": "^4.1.13",
|
||||
"webpack": "^5.74.0",
|
||||
"webpack-cli": "^5.1.0",
|
||||
"webpack-dev-server": "^5.2.2",
|
||||
|
|
|
|||
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
|
|
@ -36,13 +36,6 @@ class GeneralController extends AbstractController
|
|||
], $response);
|
||||
}
|
||||
|
||||
#[Route('/reviews', name: 'app_reviews')]
|
||||
public function app_reviews(EntityManagerInterface $em): Response
|
||||
{
|
||||
return $this->render('reviews/reviews.html.twig', [
|
||||
'posts' => $em->getRepository(Post::class)->findBycat('blog', 3)
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/professional-support', name: 'app_professional_support')]
|
||||
public function app_professional_support(): Response
|
||||
|
|
|
|||
62
tailwind.config.js
Normal file
62
tailwind.config.js
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./templates/**/*.html.twig",
|
||||
"./assets/**/*.js",
|
||||
"./src/**/*.php",
|
||||
"./public/**/*.html"
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
'yekan': ['Yekan Bakh FaNum', 'Tahoma', 'Arial', 'sans-serif'],
|
||||
},
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#eff6ff',
|
||||
100: '#dbeafe',
|
||||
200: '#bfdbfe',
|
||||
300: '#93c5fd',
|
||||
400: '#60a5fa',
|
||||
500: '#3b82f6',
|
||||
600: '#1743bb',
|
||||
700: '#1d4ed8',
|
||||
800: '#1e40af',
|
||||
900: '#1e3a8a',
|
||||
},
|
||||
secondary: {
|
||||
50: '#f8fafc',
|
||||
100: '#f1f5f9',
|
||||
200: '#e2e8f0',
|
||||
300: '#cbd5e1',
|
||||
400: '#94a3b8',
|
||||
500: '#64748b',
|
||||
600: '#475569',
|
||||
700: '#334155',
|
||||
800: '#1e293b',
|
||||
900: '#0f172a',
|
||||
}
|
||||
},
|
||||
spacing: {
|
||||
'18': '4.5rem',
|
||||
'88': '22rem',
|
||||
},
|
||||
borderRadius: {
|
||||
'4xl': '2rem',
|
||||
},
|
||||
boxShadow: {
|
||||
'soft': '0 2px 15px -3px rgba(0, 0, 0, 0.07), 0 10px 20px -2px rgba(0, 0, 0, 0.04)',
|
||||
'medium': '0 4px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
|
||||
}
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
require('@tailwindcss/forms'),
|
||||
require('@tailwindcss/typography'),
|
||||
],
|
||||
// RTL Support
|
||||
corePlugins: {
|
||||
// Disable default direction utilities
|
||||
direction: false,
|
||||
},
|
||||
}
|
||||
|
|
@ -15,7 +15,6 @@ function gtag() {
|
|||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-K1R1SYQY8E');
|
||||
</script>
|
||||
{% if block('des') is not defined %}
|
||||
|
|
@ -99,6 +98,111 @@ gtag('config', 'G-K1R1SYQY8E');
|
|||
50% { opacity: 0.5; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
/* استایلهای هدر جدید */
|
||||
header {
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
/* انیمیشن hover برای لینکها */
|
||||
.nav-link {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.nav-link::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(59, 130, 246, 0.1), transparent);
|
||||
transition: left 0.5s;
|
||||
}
|
||||
|
||||
.nav-link:hover::before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
/* بهبود dropdown ها */
|
||||
.group:hover .group-hover\:opacity-100 {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:visible {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:translate-y-0 {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* انیمیشن برای دکمهها */
|
||||
.btn-primary {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn-primary::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
transition: left 0.5s;
|
||||
}
|
||||
|
||||
.btn-primary:hover::before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
/* بهبود responsive */
|
||||
@media (max-width: 1024px) {
|
||||
header .container {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* انیمیشن برای لوگو */
|
||||
.logo-container {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.logo-container:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* مدیریت responsive منو */
|
||||
#desktopMenu {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
#desktopMenu {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
/* مخفی کردن دکمه منوی موبایل در دسکتاپ */
|
||||
#mobileMenuButton {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1023px) {
|
||||
#desktopMenu {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* نمایش دکمه منوی موبایل در موبایل */
|
||||
#mobileMenuButton {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
|
|
@ -175,149 +279,266 @@ gtag('config', 'G-K1R1SYQY8E');
|
|||
}
|
||||
}, 3000);
|
||||
});
|
||||
|
||||
// تابع toggle برای mobile menu
|
||||
function toggleMobileMenu() {
|
||||
const menu = document.getElementById('navbarSupportedContent');
|
||||
if (menu.classList.contains('hidden')) {
|
||||
menu.classList.remove('hidden');
|
||||
} else {
|
||||
menu.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
// مدیریت نمایش منو بر اساس اندازه صفحه
|
||||
function handleResponsiveMenu() {
|
||||
const mobileMenu = document.getElementById('navbarSupportedContent');
|
||||
|
||||
if (window.innerWidth >= 1024) {
|
||||
// دسکتاپ - مخفی کردن منوی موبایل
|
||||
if (mobileMenu) {
|
||||
mobileMenu.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// اجرا در بارگذاری صفحه
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
handleResponsiveMenu();
|
||||
});
|
||||
|
||||
// اجرا در تغییر اندازه صفحه
|
||||
window.addEventListener('resize', function() {
|
||||
handleResponsiveMenu();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg border-bottom bg-body-tertiary shadow-sm">
|
||||
<div class="container">
|
||||
<a class="navbar-brand text-primary d-flex align-items-center gap-2" href="{{path('app_home')}}">
|
||||
<img src="{{asset('/favicon/favicon.svg')}}" alt="نرم افزار حسابداری آنلاین حسابیکس" width="30" height="30">
|
||||
<span class="">حسابیکس</span>
|
||||
<!-- هدر جدید با طراحی مدرن -->
|
||||
<header class="bg-white/95 backdrop-blur-md border-b border-gray-100 shadow-lg sticky top-0 z-50">
|
||||
<div class="container mx-auto px-4 lg:px-6">
|
||||
<div class="flex items-center justify-between h-16">
|
||||
<!-- لوگو و نام برند -->
|
||||
<div class="flex items-center space-x-3 space-x-reverse">
|
||||
<a href="{{path('app_home')}}" class="flex items-center space-x-3 space-x-reverse group logo-container">
|
||||
<div class="relative">
|
||||
<img src="{{asset('/favicon/favicon.svg')}}"
|
||||
alt="نرم افزار حسابداری آنلاین حسابیکس"
|
||||
width="36" height="36"
|
||||
class="transition-transform duration-300 group-hover:scale-110">
|
||||
<div class="absolute -top-1 -right-1 w-2.5 h-2.5 bg-green-500 rounded-full animate-pulse"></div>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-xl font-bold bg-gradient-to-l from-blue-600 to-purple-600 bg-clip-text text-transparent">
|
||||
حسابیکس
|
||||
</span>
|
||||
<span class="text-xs text-gray-500 -mt-0.5">نرمافزار حسابداری آنلاین</span>
|
||||
</div>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav ms-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link px-3 py-2 rounded-3 transition-all" href="{{path('app_guide')}}">راهنمای جامع</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link px-3 py-2 rounded-3 transition-all" href="{{path('app_professional_support')}}">پشتیبانی سازمانی</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link px-3 py-2 rounded-3 transition-all" href="{{path('app_blog_home')}}">وبلاگ</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link px-3 py-2 rounded-3 transition-all" href="{{path('qa_index')}}">سوالات</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link px-3 py-2 rounded-3 transition-all" href="{{path('app_page',{'url':'sponsors'})}}">حامیان مالی</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link px-3 py-2 rounded-3 transition-all dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
درباره ما
|
||||
</div>
|
||||
|
||||
<!-- منوی اصلی - دسکتاپ -->
|
||||
<nav id="desktopMenu" class="items-center space-x-1 space-x-reverse">
|
||||
<a href="{{path('app_guide')}}"
|
||||
class="nav-link px-3 py-2 text-gray-700 hover:text-blue-600 hover:bg-blue-50 rounded-lg transition-all duration-200 font-medium text-sm">
|
||||
راهنمای جامع
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{path('app_page',{'url':'about'})}}">داستان حسابیکس</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{path('app_page',{'url':'contact'})}}">تماس با ما</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="{{path('app_professional_support')}}"
|
||||
class="nav-link px-3 py-2 text-gray-700 hover:text-blue-600 hover:bg-blue-50 rounded-lg transition-all duration-200 font-medium text-sm">
|
||||
پشتیبانی سازمانی
|
||||
</a>
|
||||
<a href="{{path('app_blog_home')}}"
|
||||
class="nav-link px-3 py-2 text-gray-700 hover:text-blue-600 hover:bg-blue-50 rounded-lg transition-all duration-200 font-medium text-sm">
|
||||
وبلاگ
|
||||
</a>
|
||||
<a href="{{path('qa_index')}}"
|
||||
class="nav-link px-3 py-2 text-gray-700 hover:text-blue-600 hover:bg-blue-50 rounded-lg transition-all duration-200 font-medium text-sm">
|
||||
سوالات
|
||||
</a>
|
||||
<a href="{{path('app_page',{'url':'sponsors'})}}"
|
||||
class="nav-link px-3 py-2 text-gray-700 hover:text-blue-600 hover:bg-blue-50 rounded-lg transition-all duration-200 font-medium text-sm">
|
||||
حامیان مالی
|
||||
</a>
|
||||
<a href="{{path('app_page',{'url':'about'})}}"
|
||||
class="nav-link px-3 py-2 text-gray-700 hover:text-blue-600 hover:bg-blue-50 rounded-lg transition-all duration-200 font-medium text-sm">
|
||||
داستان حسابیکس
|
||||
</a>
|
||||
<a href="{{path('app_page',{'url':'contact'})}}"
|
||||
class="nav-link px-3 py-2 text-gray-700 hover:text-blue-600 hover:bg-blue-50 rounded-lg transition-all duration-200 font-medium text-sm">
|
||||
تماس با ما
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<!-- دکمههای کاربر -->
|
||||
<div class="flex items-center space-x-3 space-x-reverse">
|
||||
{% if app.user and app.user.roles is defined and 'ROLE_CUSTOMER' in app.user.roles %}
|
||||
{# کاربر وارد شده - نمایش منوی داشبورد #}
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-primary rounded-4 px-3 py-2 fw-bold transition-all dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<img src="{{ asset('/img/icons/user.svg') }}" alt="کاربر" class="icon-svg icon-user me-2">{{ app.user.name }}
|
||||
<!-- کاربر وارد شده -->
|
||||
<div class="relative group">
|
||||
<button class="flex items-center space-x-2 space-x-reverse px-3 py-2 bg-gradient-to-l from-blue-50 to-purple-50 text-gray-700 rounded-lg hover:from-blue-100 hover:to-purple-100 transition-all duration-200 border border-blue-200">
|
||||
<div class="w-7 h-7 bg-gradient-to-l from-blue-500 to-purple-500 rounded-full flex items-center justify-center">
|
||||
<span class="text-white text-xs font-bold">{{ app.user.name|slice(0,1) }}</span>
|
||||
</div>
|
||||
<span class="font-medium text-sm">{{ app.user.name }}</span>
|
||||
<svg class="w-3 h-3 transition-transform duration-200 group-hover:rotate-180" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{ path('customer_dashboard') }}">
|
||||
<img src="{{ asset('/img/icons/cogs.svg') }}" alt="داشبورد" class="icon-svg icon-cogs me-2">داشبورد
|
||||
<div class="absolute left-0 mt-2 w-56 bg-white rounded-xl shadow-xl border border-gray-100 py-3 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-300 transform translate-y-2 group-hover:translate-y-0">
|
||||
<div class="px-4 py-2 border-b border-gray-100">
|
||||
<div class="text-sm font-medium text-gray-900">{{ app.user.name }}</div>
|
||||
<div class="text-xs text-gray-500">عضو باشگاه مشتریان</div>
|
||||
</div>
|
||||
<a href="{{ path('customer_dashboard') }}"
|
||||
class="flex items-center space-x-3 space-x-reverse px-4 py-3 text-gray-700 hover:bg-blue-50 hover:text-blue-600 transition-colors duration-200">
|
||||
<div class="w-7 h-7 bg-blue-100 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-3.5 h-3.5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2H5a2 2 0 00-2-2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="text-sm">داشبورد</span>
|
||||
</a>
|
||||
</li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li>
|
||||
<a class="dropdown-item text-danger" href="{{ path('customer_logout') }}">
|
||||
<img src="{{ asset('/img/icons/sign-out.svg') }}" alt="خروج" class="icon-svg icon-sign-out me-2">خروج
|
||||
<div class="px-4 py-2">
|
||||
<a href="{{ path('customer_logout') }}"
|
||||
class="flex items-center space-x-3 space-x-reverse px-3 py-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors duration-200">
|
||||
<div class="w-7 h-7 bg-red-100 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-3.5 h-3.5 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="text-sm">خروج</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
{# کاربر وارد نشده - نمایش دکمه ورود #}
|
||||
<a class="btn btn-outline-primary rounded-4 px-3 py-2 fw-bold transition-all" href="{{ path('customer_login') }}">
|
||||
<!-- کاربر وارد نشده -->
|
||||
<a href="{{ path('customer_login') }}"
|
||||
class="px-3 py-2 text-gray-700 hover:text-blue-600 hover:bg-blue-50 rounded-lg transition-all duration-200 font-medium text-sm">
|
||||
باشگاه مشتریان
|
||||
</a>
|
||||
{% endif %}
|
||||
<a target="_blank" class="btn btn-primary rounded-4 px-4 py-2 fw-bold transition-all" href="https://app.hesabix.ir">
|
||||
|
||||
<!-- دکمه ورود/عضویت -->
|
||||
<a target="_blank"
|
||||
href="https://app.hesabix.ir"
|
||||
class="btn-primary px-5 py-2 bg-gradient-to-l from-blue-600 to-purple-600 text-white rounded-lg hover:from-blue-700 hover:to-purple-700 transition-all duration-200 font-medium text-sm shadow-lg hover:shadow-xl transform hover:-translate-y-0.5">
|
||||
ورود / عضویت
|
||||
</a>
|
||||
|
||||
<!-- دکمه منوی موبایل -->
|
||||
<button id="mobileMenuButton" class="lg:hidden p-2 rounded-lg hover:bg-gray-100 transition-colors duration-200"
|
||||
type="button"
|
||||
onclick="toggleMobileMenu()"
|
||||
aria-label="Toggle navigation">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- منوی موبایل -->
|
||||
<div class="lg:hidden hidden" id="navbarSupportedContent">
|
||||
<div class="py-4 border-t border-gray-100">
|
||||
<div class="space-y-1">
|
||||
<a href="{{path('app_guide')}}"
|
||||
class="block px-4 py-3 text-gray-700 hover:bg-blue-50 hover:text-blue-600 rounded-lg transition-colors duration-200">
|
||||
راهنمای جامع
|
||||
</a>
|
||||
<a href="{{path('app_professional_support')}}"
|
||||
class="block px-4 py-3 text-gray-700 hover:bg-blue-50 hover:text-blue-600 rounded-lg transition-colors duration-200">
|
||||
پشتیبانی سازمانی
|
||||
</a>
|
||||
<a href="{{path('app_blog_home')}}"
|
||||
class="block px-4 py-3 text-gray-700 hover:bg-blue-50 hover:text-blue-600 rounded-lg transition-colors duration-200">
|
||||
وبلاگ
|
||||
</a>
|
||||
<a href="{{path('qa_index')}}"
|
||||
class="block px-4 py-3 text-gray-700 hover:bg-blue-50 hover:text-blue-600 rounded-lg transition-colors duration-200">
|
||||
سوالات
|
||||
</a>
|
||||
<a href="{{path('app_page',{'url':'sponsors'})}}"
|
||||
class="block px-4 py-3 text-gray-700 hover:bg-blue-50 hover:text-blue-600 rounded-lg transition-colors duration-200">
|
||||
حامیان مالی
|
||||
</a>
|
||||
<a href="{{path('app_page',{'url':'about'})}}"
|
||||
class="block px-4 py-3 text-gray-700 hover:bg-blue-50 hover:text-blue-600 rounded-lg transition-colors duration-200">
|
||||
داستان حسابیکس
|
||||
</a>
|
||||
<a href="{{path('app_page',{'url':'contact'})}}"
|
||||
class="block px-4 py-3 text-gray-700 hover:bg-blue-50 hover:text-blue-600 rounded-lg transition-colors duration-200">
|
||||
تماس با ما
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
{% block body %}{% endblock %}
|
||||
|
||||
<footer class="py-3 my-4">
|
||||
<div class="d-flex justify-content-center align-items-center gap-3 mb-3" id="trust-seals-container">
|
||||
<footer class="py-6 my-8">
|
||||
<div class="flex justify-center items-center gap-3 mb-6" id="trust-seals-container">
|
||||
<!-- نشانگرهای بارگذاری -->
|
||||
<div class="trust-seal-loading d-flex gap-3">
|
||||
<div class="spinner-border spinner-border-sm text-primary" role="status" aria-hidden="true"></div>
|
||||
<span class="text-muted small">در حال بارگذاری گواهیهای اعتماد...</span>
|
||||
<div class="trust-seal-loading flex gap-3">
|
||||
<div class="spinner-border" role="status" aria-hidden="true"></div>
|
||||
<span class="text-gray-500 text-sm">در حال بارگذاری گواهیهای اعتماد...</span>
|
||||
</div>
|
||||
|
||||
<!-- محتوای اصلی که بعد از لود نمایش داده میشود -->
|
||||
<div class="trust-seals-content" style="display: none;">
|
||||
<div class="trust-seals-content hidden">
|
||||
<a referrerpolicy='origin' target='_blank' href='https://trustseal.enamad.ir/?id=614357&Code=4ATiNTREoPRD5Lz3zwc9zyz0zWGJiZL3'>
|
||||
<img referrerpolicy='origin' src='https://trustseal.enamad.ir/logo.aspx?id=614357&Code=4ATiNTREoPRD5Lz3zwc9zyz0zWGJiZL3' alt='گواهی اعتماد اناماد' style='cursor:pointer' code='4ATiNTREoPRD5Lz3zwc9zyz0zWGJiZL3' loading="lazy">
|
||||
<img referrerpolicy='origin' src='https://trustseal.enamad.ir/logo.aspx?id=614357&Code=4ATiNTREoPRD5Lz3zwc9zyz0zWGJiZL3' alt='گواهی اعتماد اناماد' class='cursor-pointer hover:opacity-80 transition-opacity duration-300 max-h-12 w-auto' code='4ATiNTREoPRD5Lz3zwc9zyz0zWGJiZL3' loading="lazy">
|
||||
</a>
|
||||
<a href="https://bitpay.ir/certificate-230498-hesabix.ir" target="_blank">
|
||||
<img src="https://bitpay.ir/theme/public/images/trusted-logo.svg" alt="گواهی اعتماد بیتپی" loading="lazy"/>
|
||||
<img src="https://bitpay.ir/theme/public/images/trusted-logo.svg" alt="گواهی اعتماد بیتپی" class="hover:opacity-80 transition-opacity duration-300 max-h-12 w-auto" loading="lazy"/>
|
||||
</a>
|
||||
<img referrerpolicy='origin' id='rgvjoeukesgtapfufukzrgvj' style='cursor:pointer' onclick='window.open("https://logo.samandehi.ir/Verify.aspx?id=380563&p=xlaomcsiobpddshwgvkaxlao", "Popup","toolbar=no, scrollbars=no, location=no, statusbar=no, menubar=no, resizable=0, width=450, height=630, top=30")' alt='گواهی اعتماد ساماندهی' src='https://logo.samandehi.ir/logo.aspx?id=380563&p=qftiaqgwlymaujynwlbqqfti' loading="lazy"/>
|
||||
<img referrerpolicy='origin' id='rgvjoeukesgtapfufukzrgvj' class='cursor-pointer hover:opacity-80 transition-opacity duration-300 max-h-12 w-auto' onclick='window.open("https://logo.samandehi.ir/Verify.aspx?id=380563&p=xlaomcsiobpddshwgvkaxlao", "Popup","toolbar=no, scrollbars=no, location=no, statusbar=no, menubar=no, resizable=0, width=450, height=630, top=30")' alt='گواهی اعتماد ساماندهی' src='https://logo.samandehi.ir/logo.aspx?id=380563&p=qftiaqgwlymaujynwlbqqfti' loading="lazy"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="nav justify-content-center border-bottom pb-3 mb-3">
|
||||
<li class="nav-item">
|
||||
<a target="_blank" href="https://azadbeh.ir/projects/%D8%AD%D8%B3%D8%A7%D8%A8%DB%8C%DA%A9%D8%B3" class="nav-link px-2">فرصتهای شغلی</a>
|
||||
<ul class="flex justify-center flex-wrap gap-4 border-b border-gray-200 pb-6 mb-6">
|
||||
<li>
|
||||
<a target="_blank" href="https://azadbeh.ir/projects/%D8%AD%D8%B3%D8%A7%D8%A8%DB%8C%DA%A9%D8%B3" class="text-gray-600 hover:text-primary-600 px-2 py-1 transition-colors duration-200">فرصتهای شغلی</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{path('app_page',{'url':'hsx'})}}" class="nav-link px-2">توکن HSX</a>
|
||||
<li>
|
||||
<a href="{{path('app_page',{'url':'hsx'})}}" class="text-gray-600 hover:text-primary-600 px-2 py-1 transition-colors duration-200">توکن HSX</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{path('app_api_docs',{'url':'home'})}}" class="nav-link px-2">مستندات API</a>
|
||||
<li>
|
||||
<a href="{{path('app_api_docs',{'url':'home'})}}" class="text-gray-600 hover:text-primary-600 px-2 py-1 transition-colors duration-200">مستندات API</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{path('app_changes')}}" class="nav-link px-2">تغییرات</a>
|
||||
<li>
|
||||
<a href="{{path('app_changes')}}" class="text-gray-600 hover:text-primary-600 px-2 py-1 transition-colors duration-200">تغییرات</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="https://source.hesabix.ir/morrning" target="_blank" class="nav-link px-2">مخازن کد</a>
|
||||
<li>
|
||||
<a href="https://source.hesabix.ir/morrning" target="_blank" class="text-gray-600 hover:text-primary-600 px-2 py-1 transition-colors duration-200">مخازن کد</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{path('app_page',{'url':'open-source'})}}" class="nav-link px-2">متنباز</a>
|
||||
<li>
|
||||
<a href="{{path('app_page',{'url':'open-source'})}}" class="text-gray-600 hover:text-primary-600 px-2 py-1 transition-colors duration-200">متنباز</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{path('app_page',{'url':'inMedia'})}}" class="nav-link px-2">در رسانهها</a>
|
||||
<li>
|
||||
<a href="{{path('app_page',{'url':'inMedia'})}}" class="text-gray-600 hover:text-primary-600 px-2 py-1 transition-colors duration-200">در رسانهها</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{path('app_page',{'url':'terms'})}}" class="nav-link px-2">قوانین ارائه خدمات</a>
|
||||
<li>
|
||||
<a href="{{path('app_page',{'url':'terms'})}}" class="text-gray-600 hover:text-primary-600 px-2 py-1 transition-colors duration-200">قوانین ارائه خدمات</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{path('app_page',{'url':'privacy'})}}" class="nav-link px-2">حریم خصوصی</a>
|
||||
<li>
|
||||
<a href="{{path('app_page',{'url':'privacy'})}}" class="text-gray-600 hover:text-primary-600 px-2 py-1 transition-colors duration-200">حریم خصوصی</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="text-center p-1 m-1">
|
||||
<div class="row mx-0">
|
||||
<div class="col-sm-12 col-md-6 text-center text-body-tertiary">
|
||||
<img src={{asset('/img/sp/parspack.svg')}} alt="Parspack Co" width="25" class="img-fluid">
|
||||
<div class="text-center p-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="text-center text-gray-500">
|
||||
<img src={{asset('/img/sp/parspack.svg')}} alt="Parspack Co" width="25" class="inline-block">
|
||||
با خاطری آسوده،استوار بر روی راهکارهای ابری
|
||||
<a href="https://parspack.com" target="_blank" class="rul">پارسپک</a>
|
||||
<a href="https://parspack.com" target="_blank" class="text-primary-600 hover:underline">پارسپک</a>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-6 text-center text-body-tertiary">
|
||||
<div class="text-center text-gray-500">
|
||||
حسابیکس با
|
||||
<img src={{asset('/img/heart.png')}} alt="Love" width="25" class="img-fluid">
|
||||
<img src={{asset('/img/heart.png')}} alt="Love" width="25" class="inline-block">
|
||||
متن باز است
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -4,353 +4,78 @@
|
|||
|
||||
{% block stylesheets %}
|
||||
{{ parent() }}
|
||||
<style>
|
||||
/* تنظیمات کلی برای فارسی */
|
||||
.customer-dashboard * {
|
||||
font-family: 'Yekan Bakh FaNum', 'Tahoma', 'Arial', sans-serif;
|
||||
}
|
||||
|
||||
.customer-dashboard {
|
||||
min-height: 80vh;
|
||||
padding: 40px 0;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.dashboard-header {
|
||||
background: linear-gradient(135deg, #0d6efd 0%, #6610f2 100%);
|
||||
color: white;
|
||||
padding: 40px 0;
|
||||
margin-bottom: 40px;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.dashboard-header h1 {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.dashboard-header p {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.dashboard-card {
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||||
padding: 30px;
|
||||
margin-bottom: 30px;
|
||||
transition: transform 0.3s ease;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.dashboard-card:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
.dashboard-card h3 {
|
||||
color: #0d6efd;
|
||||
margin-bottom: 20px;
|
||||
font-weight: bold;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px 0;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.info-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
color: #6c757d;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 5px 15px;
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.status-active {
|
||||
background: #d1edff;
|
||||
color: #0c5460;
|
||||
}
|
||||
|
||||
.status-inactive {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
margin-top: 30px;
|
||||
direction: rtl;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.btn-customer {
|
||||
background: linear-gradient(135deg, #0d6efd 0%, #6610f2 100%);
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
padding: 12px 25px;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
margin: 5px;
|
||||
display: inline-block;
|
||||
transition: all 0.3s ease;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.btn-customer:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(13, 110, 253, 0.4);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.welcome-message {
|
||||
background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 30px;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.welcome-message h4 {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.welcome-message p {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* بهبود نمایش آیکونهای SVG */
|
||||
.icon-svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-left: 5px;
|
||||
margin-right: 0;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* تغییر رنگ آیکونهای SVG */
|
||||
.icon-svg svg {
|
||||
fill: currentColor;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* رنگهای مختلف برای آیکونها */
|
||||
.text-primary .icon-svg svg {
|
||||
fill: #0d6efd;
|
||||
}
|
||||
|
||||
.text-success .icon-svg svg {
|
||||
fill: #198754;
|
||||
}
|
||||
|
||||
.text-danger .icon-svg svg {
|
||||
fill: #dc3545;
|
||||
}
|
||||
|
||||
.text-warning .icon-svg svg {
|
||||
fill: #ffc107;
|
||||
}
|
||||
|
||||
.text-info .icon-svg svg {
|
||||
fill: #0dcaf0;
|
||||
}
|
||||
|
||||
.text-muted .icon-svg svg {
|
||||
fill: #6c757d;
|
||||
}
|
||||
|
||||
.text-white .icon-svg svg {
|
||||
fill: #ffffff;
|
||||
}
|
||||
|
||||
/* بهبود نمایش متنهای فارسی */
|
||||
.text-center {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.text-end {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* استایلهای کیف پول */
|
||||
.wallet-connect-form {
|
||||
background: #ffffff;
|
||||
padding: 25px;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 25px;
|
||||
border: 1px solid #e9ecef;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.wallet-connect-form h5 {
|
||||
color: #0d6efd;
|
||||
margin-bottom: 20px;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#walletAddress {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 14px;
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#walletAddress:read-only {
|
||||
background-color: #f8f9fa;
|
||||
cursor: not-allowed;
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.wallet-connect-form .input-group-text {
|
||||
background-color: #e9ecef;
|
||||
border: 1px solid #e9ecef;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.wallet-connect-form .btn-lg {
|
||||
padding: 12px 24px;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wallet-connect-form .btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.wallets-list table {
|
||||
direction: rtl;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.wallets-list th,
|
||||
.wallets-list td {
|
||||
text-align: right;
|
||||
vertical-align: middle;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.wallets-list th {
|
||||
background-color: #f8f9fa;
|
||||
font-weight: 600;
|
||||
border-bottom: 2px solid #dee2e6;
|
||||
}
|
||||
|
||||
.wallets-list code {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
background: #f8f9fa;
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.btn-group-sm .btn {
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.btn-group-sm .btn i {
|
||||
margin-left: 4px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="customer-dashboard">
|
||||
<div class="container">
|
||||
<div class="welcome-message">
|
||||
<h4><img src="{{ asset('/img/icons/heart.svg') }}" alt="قلب" class="icon-svg icon-heart"> از عضویت شما در باشگاه مشتریان حسابیکس سپاسگزاریم!</h4>
|
||||
<div class="min-h-screen py-10 font-yekan" dir="rtl">
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="bg-gradient-to-r from-green-500 to-teal-500 text-white p-6 rounded-xl mb-10">
|
||||
<h4 class="text-xl font-bold mb-2 flex items-center gap-2">
|
||||
<img src="{{ asset('/img/icons/heart.svg') }}" alt="قلب" class="w-5 h-5"> از عضویت شما در باشگاه مشتریان حسابیکس سپاسگزاریم!
|
||||
</h4>
|
||||
<p class="mb-0">در این بخش میتوانید اطلاعات حساب کاربری خود را مشاهده و مدیریت کنید.</p>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="dashboard-card">
|
||||
<h3><img src="{{ asset('/img/icons/user.svg') }}" alt="کاربر" class="icon-svg icon-user"> اطلاعات شخصی</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="w-full">
|
||||
<div class="card hover:shadow-lg transition-shadow duration-300">
|
||||
<h3 class="text-primary-600 mb-6 text-xl font-bold flex items-center gap-2">
|
||||
<img src="{{ asset('/img/icons/user.svg') }}" alt="کاربر" class="w-5 h-5"> اطلاعات شخصی
|
||||
</h3>
|
||||
|
||||
<div class="info-item">
|
||||
<span class="info-label">نام و نام خانوادگی:</span>
|
||||
<span class="info-value">{{ user.name }}</span>
|
||||
<div class="flex justify-between items-center py-4 border-b border-gray-200">
|
||||
<span class="font-semibold text-gray-700">نام و نام خانوادگی:</span>
|
||||
<span class="text-gray-600">{{ user.name }}</span>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<span class="info-label">پست الکترونیکی:</span>
|
||||
<span class="info-value">{{ user.email }}</span>
|
||||
<div class="flex justify-between items-center py-4 border-b border-gray-200">
|
||||
<span class="font-semibold text-gray-700">پست الکترونیکی:</span>
|
||||
<span class="text-gray-600">{{ user.email }}</span>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<span class="info-label">شماره موبایل:</span>
|
||||
<span class="info-value">{{ user.phone }}</span>
|
||||
<div class="flex justify-between items-center py-4 border-b border-gray-200">
|
||||
<span class="font-semibold text-gray-700">شماره موبایل:</span>
|
||||
<span class="text-gray-600">{{ user.phone }}</span>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<span class="info-label">وضعیت حساب:</span>
|
||||
<span class="status-badge {{ user.isActive ? 'status-active' : 'status-inactive' }}">
|
||||
<div class="flex justify-between items-center py-4">
|
||||
<span class="font-semibold text-gray-700">وضعیت حساب:</span>
|
||||
<span class="px-4 py-2 rounded-full text-sm font-bold {{ user.isActive ? 'bg-blue-100 text-blue-800' : 'bg-red-100 text-red-800' }}">
|
||||
{{ user.isActive ? 'فعال' : 'غیرفعال' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="dashboard-card">
|
||||
<h3><img src="{{ asset('/img/icons/calendar.svg') }}" alt="تقویم" class="icon-svg icon-calendar"> اطلاعات عضویت</h3>
|
||||
<div class="w-full">
|
||||
<div class="card hover:shadow-lg transition-shadow duration-300">
|
||||
<h3 class="text-primary-600 mb-6 text-xl font-bold flex items-center gap-2">
|
||||
<img src="{{ asset('/img/icons/calendar.svg') }}" alt="تقویم" class="w-5 h-5"> اطلاعات عضویت
|
||||
</h3>
|
||||
|
||||
<div class="info-item">
|
||||
<span class="info-label">تاریخ عضویت:</span>
|
||||
<span class="info-value">{{ user.createdAt|date('Y/m/d') }}</span>
|
||||
<div class="flex justify-between items-center py-4 border-b border-gray-200">
|
||||
<span class="font-semibold text-gray-700">تاریخ عضویت:</span>
|
||||
<span class="text-gray-600">{{ user.createdAt|date('Y/m/d') }}</span>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<span class="info-label">آخرین ورود:</span>
|
||||
<span class="info-value">
|
||||
<div class="flex justify-between items-center py-4">
|
||||
<span class="font-semibold text-gray-700">آخرین ورود:</span>
|
||||
<span class="text-gray-600">
|
||||
{{ user.lastLoginAt ? user.lastLoginAt|date('Y/m/d H:i') : 'هنوز وارد نشده' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<span class="info-label">تایید ایمیل:</span>
|
||||
<span class="status-badge {{ user.emailVerifiedAt ? 'status-active' : 'status-inactive' }}">
|
||||
<div class="flex justify-between items-center py-4 border-b border-gray-200">
|
||||
<span class="font-semibold text-gray-700">تایید ایمیل:</span>
|
||||
<span class="px-4 py-2 rounded-full text-sm font-bold {{ user.emailVerifiedAt ? 'bg-blue-100 text-blue-800' : 'bg-red-100 text-red-800' }}">
|
||||
{{ user.emailVerifiedAt ? 'تایید شده' : 'تایید نشده' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% if user.subscriptionType %}
|
||||
<div class="info-item">
|
||||
<span class="info-label">نوع اشتراک:</span>
|
||||
<span class="info-value">{{ user.subscriptionType }}</span>
|
||||
<div class="flex justify-between items-center py-4">
|
||||
<span class="font-semibold text-gray-700">نوع اشتراک:</span>
|
||||
<span class="text-gray-600">{{ user.subscriptionType }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
@ -358,21 +83,22 @@
|
|||
</div>
|
||||
|
||||
<!-- بخش کیف پولها -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-card wallet-section">
|
||||
<h3><img src="{{ asset('/img/icons/wallet.svg') }}" alt="کیف پول" class="icon-svg icon-wallet"> مدیریت کیف پولها</h3>
|
||||
<div class="w-full mt-8">
|
||||
<div class="card">
|
||||
<h3 class="text-primary-600 mb-6 text-xl font-bold flex items-center gap-2">
|
||||
<img src="{{ asset('/img/icons/wallet.svg') }}" alt="کیف پول" class="w-5 h-5"> مدیریت کیف پولها
|
||||
</h3>
|
||||
|
||||
<!-- فرم اتصال کیف پول جدید -->
|
||||
<div class="wallet-connect-form mb-4"
|
||||
<div class="bg-white p-6 rounded-xl border border-gray-200 mb-6"
|
||||
data-controller="wallet-connect"
|
||||
data-wallet-connect-sign-message-value="{{ signMessage }}"
|
||||
data-wallet-connect-csrf-token-value="{{ csrf_token('wallet_connect_form') }}">
|
||||
<h5>اتصال کیف پول جدید</h5>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<h5 class="text-lg font-semibold mb-4">اتصال کیف پول جدید</h5>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label for="walletType" class="form-label">نوع کیف پول</label>
|
||||
<select class="form-select" id="walletType" data-wallet-connect-target="walletType" data-action="change->wallet-connect#onWalletTypeChange">
|
||||
<select class="form-control" id="walletType" data-wallet-connect-target="walletType" data-action="change->wallet-connect#onWalletTypeChange">
|
||||
<option value="">انتخاب کنید...</option>
|
||||
<option value="metamask">MetaMask</option>
|
||||
<option value="trust">Trust Wallet</option>
|
||||
|
|
@ -381,24 +107,24 @@
|
|||
<option value="other">سایر</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div>
|
||||
<label class="form-label">آدرس کیف پول</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">
|
||||
<i class="fas fa-wallet"></i>
|
||||
</span>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
|
||||
<i class="fas fa-wallet text-gray-400"></i>
|
||||
</div>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
class="form-control pr-10"
|
||||
id="walletAddress"
|
||||
data-wallet-connect-target="walletAddress"
|
||||
placeholder="آدرس کیف پول پس از اتصال نمایش داده میشود"
|
||||
readonly>
|
||||
</div>
|
||||
<div class="form-text">آدرس کیف پول شما پس از اتصال به صورت خودکار پر میشود</div>
|
||||
<p class="text-sm text-gray-500 mt-2">آدرس کیف پول شما پس از اتصال به صورت خودکار پر میشود</p>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="col-span-2">
|
||||
<button type="button"
|
||||
class="btn btn-primary btn-lg w-100"
|
||||
class="btn-primary w-full py-3 text-lg"
|
||||
id="connectBtn"
|
||||
data-wallet-connect-target="connectBtn"
|
||||
data-action="click->wallet-connect#connectWallet"
|
||||
|
|
@ -411,57 +137,57 @@
|
|||
</div>
|
||||
|
||||
<!-- لیست کیف پولهای متصل -->
|
||||
<div class="wallets-list">
|
||||
<h5>کیف پولهای متصل ({{ user.wallets|length }}/5)</h5>
|
||||
<div class="mt-6">
|
||||
<h5 class="text-lg font-semibold mb-4">کیف پولهای متصل ({{ user.wallets|length }}/5)</h5>
|
||||
|
||||
{% if user.wallets|length > 0 %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th>آدرس کیف پول</th>
|
||||
<th>نوع</th>
|
||||
<th>وضعیت</th>
|
||||
<th>تاریخ اتصال</th>
|
||||
<th>عملیات</th>
|
||||
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">آدرس کیف پول</th>
|
||||
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">نوع</th>
|
||||
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">وضعیت</th>
|
||||
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">تاریخ اتصال</th>
|
||||
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">عملیات</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
{% for wallet in user.wallets %}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ wallet.shortAddress }}</code>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<code class="text-sm bg-gray-100 px-2 py-1 rounded">{{ wallet.shortAddress }}</code>
|
||||
{% if wallet.isPrimary %}
|
||||
<span class="badge bg-primary ms-2">اصلی</span>
|
||||
<span class="bg-primary-100 text-primary-800 text-xs px-2 py-1 rounded-full mr-2">اصلی</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-info">{{ wallet.walletType }}</span>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||
<span class="bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded-full">{{ wallet.walletType }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge {{ wallet.isActive ? 'bg-success' : 'bg-danger' }}">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||
<span class="px-2 py-1 rounded-full text-xs font-medium {{ wallet.isActive ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800' }}">
|
||||
{{ wallet.isActive ? 'فعال' : 'غیرفعال' }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ wallet.connectedAt|date('Y/m/d H:i') }}</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ wallet.connectedAt|date('Y/m/d H:i') }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||
<div class="flex gap-2">
|
||||
{% if not wallet.isPrimary and wallet.isActive %}
|
||||
<button class="btn btn-outline-primary btn-sm"
|
||||
<button class="btn-outline-primary text-xs px-3 py-1"
|
||||
data-wallet-id="{{ wallet.id }}"
|
||||
data-action="click->wallet-connect#setPrimaryWallet">
|
||||
<i class="fas fa-star"></i> اصلی
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
<button class="btn btn-outline-warning btn-sm"
|
||||
<button class="btn-outline-warning text-xs px-3 py-1"
|
||||
data-wallet-id="{{ wallet.id }}"
|
||||
data-action="click->wallet-connect#toggleWalletStatus">
|
||||
<i class="fas fa-{{ wallet.isActive ? 'pause' : 'play' }}"></i>
|
||||
{{ wallet.isActive ? 'غیرفعال' : 'فعال' }}
|
||||
</button>
|
||||
|
||||
<button class="btn btn-outline-danger btn-sm"
|
||||
<button class="btn-outline-danger text-xs px-3 py-1"
|
||||
data-wallet-id="{{ wallet.id }}"
|
||||
data-action="click->wallet-connect#deleteWallet">
|
||||
<i class="fas fa-trash"></i> حذف
|
||||
|
|
@ -474,10 +200,10 @@
|
|||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center text-muted py-5">
|
||||
<i class="fas fa-wallet fa-4x mb-4 text-muted"></i>
|
||||
<h5 class="text-muted">هنوز هیچ کیف پولی متصل نشده است</h5>
|
||||
<p class="text-muted">برای شروع، نوع کیف پول خود را انتخاب کنید و روی دکمه اتصال کلیک کنید</p>
|
||||
<div class="text-center text-gray-500 py-12">
|
||||
<i class="fas fa-wallet text-6xl mb-4 text-gray-300"></i>
|
||||
<h5 class="text-gray-500 text-lg mb-2">هنوز هیچ کیف پولی متصل نشده است</h5>
|
||||
<p class="text-gray-400">برای شروع، نوع کیف پول خود را انتخاب کنید و روی دکمه اتصال کلیک کنید</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
@ -485,29 +211,29 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-card">
|
||||
<h3><img src="{{ asset('/img/icons/cogs.svg') }}" alt="تنظیمات" class="icon-svg icon-cogs"> عملیات</h3>
|
||||
<div class="w-full mt-8">
|
||||
<div class="card">
|
||||
<h3 class="text-primary-600 mb-6 text-xl font-bold flex items-center gap-2">
|
||||
<img src="{{ asset('/img/icons/cogs.svg') }}" alt="تنظیمات" class="w-5 h-5"> عملیات
|
||||
</h3>
|
||||
|
||||
<div class="action-buttons">
|
||||
<a href="{{ path('customer_forgot_password') }}" class="btn-customer">
|
||||
<img src="{{ asset('/img/icons/key.svg') }}" alt="کلید" class="icon-svg icon-key"> بازیابی کلمه عبور
|
||||
<div class="flex flex-wrap gap-4 justify-center">
|
||||
<a href="{{ path('customer_forgot_password') }}" class="btn-primary flex items-center gap-2">
|
||||
<img src="{{ asset('/img/icons/key.svg') }}" alt="کلید" class="w-4 h-4"> بازیابی کلمه عبور
|
||||
</a>
|
||||
|
||||
<a href="{{ path('app_home') }}" class="btn-customer">
|
||||
<img src="{{ asset('/img/icons/home.svg') }}" alt="خانه" class="icon-svg icon-home"> بازگشت به صفحه اصلی
|
||||
<a href="{{ path('app_home') }}" class="btn-primary flex items-center gap-2">
|
||||
<img src="{{ asset('/img/icons/home.svg') }}" alt="خانه" class="w-4 h-4"> بازگشت به صفحه اصلی
|
||||
</a>
|
||||
|
||||
<a href="{{ path('customer_logout') }}" class="btn-customer" style="background: linear-gradient(135deg, #dc3545 0%, #c82333 100%);">
|
||||
<img src="{{ asset('/img/icons/sign-out.svg') }}" alt="خروج" class="icon-svg icon-sign-out"> خروج
|
||||
<a href="{{ path('customer_logout') }}" class="bg-gradient-to-r from-red-500 to-red-600 text-white px-6 py-3 rounded-lg font-medium transition-all duration-300 hover:shadow-lg hover:-translate-y-0.5 flex items-center gap-2">
|
||||
<img src="{{ asset('/img/icons/sign-out.svg') }}" alt="خروج" class="w-4 h-4"> خروج
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -8,117 +8,165 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<main class="container-fluid px-0">
|
||||
<div class="blog-header position-relative">
|
||||
<div class="overlay"></div>
|
||||
<div class="container position-relative">
|
||||
<div class="row min-vh-50 align-items-center">
|
||||
<div class="col-12 text-center text-white">
|
||||
<h1 class="display-4 fw-bold mb-4">وبلاگ حسابیکس</h1>
|
||||
<p class="" style="font-family: 'Yekan Bakh FaNum', sans-serif;">جدیدترین اطلاعات و خبرها از دنیای حسابداری</p>
|
||||
</div>
|
||||
<main class="min-h-screen bg-gray-50">
|
||||
<!-- هدر وبلاگ -->
|
||||
<div class="relative bg-gradient-to-br from-blue-600 via-purple-600 to-indigo-700 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-black/40"></div>
|
||||
<div class="relative container mx-auto px-4 py-20 lg:py-24">
|
||||
<div class="text-center text-white">
|
||||
<h1 class="text-4xl lg:text-6xl font-bold mb-6 animate-fade-in-up">
|
||||
وبلاگ حسابیکس
|
||||
</h1>
|
||||
<p class="text-lg lg:text-xl text-blue-100 max-w-2xl mx-auto animate-fade-in-up" style="animation-delay: 0.2s;">
|
||||
جدیدترین اطلاعات و خبرها از دنیای حسابداری
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container mt-5 mb-5">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="row g-4">
|
||||
<!-- محتوای اصلی -->
|
||||
<div class="container mx-auto px-4 py-12">
|
||||
<!-- جستجو -->
|
||||
<div class="mb-8">
|
||||
<form method="GET" action="{{ path('app_blog_home') }}" class="max-w-md mx-auto">
|
||||
<div class="relative">
|
||||
<input type="text"
|
||||
name="search"
|
||||
value="{{ search }}"
|
||||
placeholder="جستجو در وبلاگ..."
|
||||
class="w-full px-4 py-3 pr-12 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 text-right">
|
||||
<button type="submit"
|
||||
class="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-blue-600 transition-colors duration-200">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- لیست پستها -->
|
||||
{% if posts|length > 0 %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mb-12">
|
||||
{% for post in posts %}
|
||||
<div class="col-md-4">
|
||||
<article class="card h-100 border-0 shadow-sm hover-shadow transition-all">
|
||||
<div class="position-relative">
|
||||
<img src="{{asset('uploaded/'~ post.mainPic)}}" alt="{{post.title}}" class="card-img-top object-fit-cover" style="height: 200px;">
|
||||
<div class="position-absolute top-0 end-0 m-3">
|
||||
<article class="group bg-white rounded-2xl shadow-soft hover:shadow-medium transition-all duration-300 overflow-hidden hover-lift">
|
||||
<!-- تصویر پست -->
|
||||
<div class="relative overflow-hidden">
|
||||
<img src="{{asset('uploaded/'~ post.mainPic)}}"
|
||||
alt="{{post.title}}"
|
||||
class="w-full h-48 object-cover group-hover:scale-105 transition-transform duration-300">
|
||||
<div class="absolute top-4 right-4 flex flex-wrap gap-2">
|
||||
{% for tree in post.tree %}
|
||||
<span class="badge bg-primary me-1">{{ tree.label }}</span>
|
||||
<span class="px-3 py-1 bg-blue-600 text-white text-xs font-medium rounded-full shadow-lg">
|
||||
{{ tree.label }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<small class="text-muted">
|
||||
<i class="fas fa-calendar-alt me-1"></i>
|
||||
{{ Jdate.jdate('Y/n/d',post.dateSubmit) }}
|
||||
</small>
|
||||
<small class="text-muted">
|
||||
<i class="fas fa-eye me-1"></i>
|
||||
{{ post.views }}
|
||||
</small>
|
||||
|
||||
<!-- محتوای کارت -->
|
||||
<div class="p-6">
|
||||
<!-- متا اطلاعات -->
|
||||
<div class="flex items-center justify-between text-sm text-gray-500 mb-4">
|
||||
<div class="flex items-center space-x-2 space-x-reverse">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
<span>{{ Jdate.jdate('Y/n/d',post.dateSubmit) }}</span>
|
||||
</div>
|
||||
<h5 class="card-title text-primary fw-bold">{{ post.title }}</h5>
|
||||
<p class="card-text text-muted">{{ post.intro }}</p>
|
||||
<a href="{{path('app_blog_post',{'url':post.url})}}" class="btn btn-primary rounded-pill stretched-link">
|
||||
ادامه مطلب
|
||||
<i class="fas fa-arrow-left me-2"></i>
|
||||
<div class="flex items-center space-x-2 space-x-reverse">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
|
||||
</svg>
|
||||
<span>{{ post.views }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- عنوان و توضیحات -->
|
||||
<h3 class="text-xl font-bold text-gray-900 mb-3 line-clamp-2 group-hover:text-blue-600 transition-colors duration-200">
|
||||
{{ post.title }}
|
||||
</h3>
|
||||
<p class="text-gray-600 mb-6 line-clamp-3 leading-relaxed">
|
||||
{{ post.intro }}
|
||||
</p>
|
||||
|
||||
<!-- دکمه ادامه مطلب -->
|
||||
<a href="{{path('app_blog_post',{'url':post.url})}}"
|
||||
class="inline-flex items-center space-x-2 space-x-reverse text-blue-600 hover:text-blue-700 font-medium transition-colors duration-200 group">
|
||||
<span>ادامه مطلب</span>
|
||||
<svg class="w-4 h-4 transform group-hover:translate-x-1 transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="row mt-5">
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination justify-content-center">
|
||||
<li class="page-item {% if page == 1 %}disabled{% endif %}">
|
||||
<a href="{{ path('app_blog_home',{'page':page -1})}}" class="page-link rounded-pill mx-1">
|
||||
<i class="fas fa-chevron-right"></i>
|
||||
صفحه قبل
|
||||
<!-- صفحهبندی -->
|
||||
{% if maxpages > 1 %}
|
||||
<nav class="flex justify-center" aria-label="صفحهبندی">
|
||||
<div class="flex items-center space-x-2 space-x-reverse">
|
||||
<!-- دکمه صفحه قبل -->
|
||||
{% if page > 1 %}
|
||||
<a href="{{ path('app_blog_home',{'page':page -1})}}"
|
||||
class="flex items-center space-x-2 space-x-reverse px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 hover:text-gray-700 transition-all duration-200">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
<span>قبلی</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a class="page-link rounded-pill mx-1 active" href="{{ path('app_blog_home',{'page':page })}}">{{page}}</a>
|
||||
</li>
|
||||
{% if (page + 1) <= maxpages %}
|
||||
<li class="page-item">
|
||||
<a class="page-link rounded-pill mx-1" href="{{ path('app_blog_home',{'page':page +1})}}">{{page +1}}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if (page + 2) <= maxpages %}
|
||||
<li class="page-item">
|
||||
<a class="page-link rounded-pill mx-1" href="{{ path('app_blog_home',{'page':page +2})}}">{{page + 2}}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if (page + 3) <= maxpages %}
|
||||
<li class="page-item">
|
||||
<a class="page-link rounded-pill mx-1" href="{{ path('app_blog_home',{'page':page +3})}}">{{page + 3}}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="page-item">
|
||||
<a href="{{ path('app_blog_home',{'page':page +1})}}" class="page-link rounded-pill mx-1 {% if (page + 1) > maxpages %}disabled{% endif %}">
|
||||
صفحه بعدی
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
|
||||
<!-- شماره صفحات -->
|
||||
<div class="flex items-center space-x-1 space-x-reverse">
|
||||
{% for i in range(1, maxpages) %}
|
||||
{% if i == page %}
|
||||
<span class="px-4 py-2 text-sm font-medium text-white bg-blue-600 border border-blue-600 rounded-lg">
|
||||
{{ i }}
|
||||
</span>
|
||||
{% elseif i <= page + 2 and i >= page - 2 %}
|
||||
<a href="{{ path('app_blog_home',{'page':i})}}"
|
||||
class="px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 hover:text-gray-700 transition-all duration-200">
|
||||
{{ i }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- دکمه صفحه بعد -->
|
||||
{% if page < maxpages %}
|
||||
<a href="{{ path('app_blog_home',{'page':page +1})}}"
|
||||
class="flex items-center space-x-2 space-x-reverse px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 hover:text-gray-700 transition-all duration-200">
|
||||
<span>بعدی</span>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
|
||||
</svg>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<!-- پیام عدم وجود پست -->
|
||||
<div class="text-center py-16">
|
||||
<div class="max-w-md mx-auto">
|
||||
<svg class="w-16 h-16 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">هیچ پستی یافت نشد</h3>
|
||||
<p class="text-gray-600">
|
||||
{% if search %}
|
||||
برای عبارت "{{ search }}" هیچ نتیجهای یافت نشد.
|
||||
{% else %}
|
||||
هنوز هیچ پستی منتشر نشده است.
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
.blog-header {
|
||||
background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('{{ asset('img/blog/blog-header.jpg') }}');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
min-height: 250px;
|
||||
}
|
||||
.hover-shadow {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.hover-shadow:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 20px rgba(0,0,0,0.1) !important;
|
||||
}
|
||||
.min-vh-50 {
|
||||
min-height: 250px;
|
||||
}
|
||||
.object-fit-cover {
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -11,119 +11,174 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<style>
|
||||
.blog-post {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.blog-post:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
.post-image {
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
.post-image:hover {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
.post-card {
|
||||
border: none;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
border-radius: 15px;
|
||||
}
|
||||
.post-card:hover {
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.recent-posts .card {
|
||||
border: none;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
border-radius: 15px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.recent-posts .card:hover {
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.recent-posts .card img {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
.recent-posts .card:hover img {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
.post-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 1.5rem;
|
||||
font-family: inherit;
|
||||
}
|
||||
.post-intro {
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.8;
|
||||
color: #555;
|
||||
}
|
||||
.post-meta {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
}
|
||||
.post-content {
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.8;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% if item.plain is not null %}
|
||||
{{ item.plain | raw}}
|
||||
{% endif %}
|
||||
{% if item.body is not null %}
|
||||
<div class="container mt-4">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-8">
|
||||
<article class="blog-post mb-4">
|
||||
<img class="img-fluid post-image mb-4" src="{{asset('uploaded/'~ item.mainPic)}}" alt="{{item.title}}"/>
|
||||
<h1 class="text-primary fs-5">{{item.title}}</h1>
|
||||
<div class="card post-card bg-body-tertiary mb-4">
|
||||
<div class="card-body">
|
||||
<div class="post-intro card-text mb-3">
|
||||
<main class="min-h-screen bg-gray-50">
|
||||
<!-- هدر پست -->
|
||||
<div class="bg-white border-b border-gray-200">
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- برچسبها -->
|
||||
{% if item.tree|length > 0 %}
|
||||
<div class="flex flex-wrap gap-2 mb-4">
|
||||
{% for tree in item.tree %}
|
||||
<span class="px-3 py-1 bg-blue-100 text-blue-800 text-sm font-medium rounded-full">
|
||||
{{ tree.label }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- عنوان -->
|
||||
<h1 class="text-3xl lg:text-4xl font-bold text-gray-900 mb-6 leading-tight">
|
||||
{{item.title}}
|
||||
</h1>
|
||||
|
||||
<!-- متا اطلاعات -->
|
||||
<div class="flex flex-wrap items-center gap-6 text-sm text-gray-600 mb-8">
|
||||
<div class="flex items-center space-x-2 space-x-reverse">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
|
||||
</svg>
|
||||
<span>توسط <strong class="text-gray-900">{{item.submitter.name}}</strong></span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2 space-x-reverse">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
<span>{{Jdate.jdate('Y/n/d',item.dateSubmit)}}</span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2 space-x-reverse">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
|
||||
</svg>
|
||||
<span>{{ item.views }} بازدید</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- محتوای اصلی -->
|
||||
<div class="container mx-auto px-4 py-12">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-12">
|
||||
<!-- محتوای پست -->
|
||||
<div class="lg:col-span-2">
|
||||
<article class="prose prose-lg max-w-none">
|
||||
<!-- تصویر اصلی -->
|
||||
<div class="mb-8">
|
||||
<img src="{{asset('uploaded/'~ item.mainPic)}}"
|
||||
alt="{{item.title}}"
|
||||
class="w-full h-64 lg:h-80 object-cover rounded-2xl shadow-lg hover:shadow-xl transition-shadow duration-300">
|
||||
</div>
|
||||
|
||||
<!-- خلاصه پست -->
|
||||
{% if item.intro %}
|
||||
<div class="bg-blue-50 border-r-4 border-blue-500 p-6 rounded-lg mb-8">
|
||||
<p class="text-lg text-gray-700 leading-relaxed font-medium">
|
||||
{{item.intro}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="post-meta card-text">
|
||||
<figure>
|
||||
<blockquote class="blockquote"></blockquote>
|
||||
<figcaption class="blockquote-footer">
|
||||
توسط
|
||||
<strong>{{item.submitter.name}}</strong>
|
||||
<cite title="Source Title">
|
||||
در تاریخ
|
||||
{{Jdate.jdate('Y/n/d',item.dateSubmit)}}
|
||||
</cite>
|
||||
</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="post-content mt-4">
|
||||
{% endif %}
|
||||
|
||||
<!-- محتوای پست -->
|
||||
<div class="prose prose-lg max-w-none text-gray-800 leading-relaxed">
|
||||
{{ item.body | raw }}
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-4">
|
||||
<div class="recent-posts">
|
||||
<h3 class="text-primary mb-3">جدیدترینها</h3>
|
||||
{% for post in posts %}
|
||||
<div class="card mb-3">
|
||||
<img src="{{asset('uploaded/'~ post.mainPic)}}" class="card-img-top" alt="{{post.title}}">
|
||||
<div class="card-body">
|
||||
<a href="{{path('app_blog_post',{'url':post.url})}}" class="stretched-link text-decoration-none">
|
||||
<h5 class="card-title text-primary">{{post.title}}</h5>
|
||||
|
||||
<!-- اشتراکگذاری -->
|
||||
<div class="mt-12 pt-8 border-t border-gray-200">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">این مطلب را به اشتراک بگذارید</h3>
|
||||
<div class="flex space-x-3 space-x-reverse">
|
||||
<a href="https://twitter.com/intent/tweet?text={{item.title|url_encode}}&url={{app.request.uri|url_encode}}"
|
||||
target="_blank"
|
||||
class="flex items-center space-x-2 space-x-reverse px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors duration-200">
|
||||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/>
|
||||
</svg>
|
||||
<span>توییتر</span>
|
||||
</a>
|
||||
<a href="https://www.linkedin.com/sharing/share-offsite/?url={{app.request.uri|url_encode}}"
|
||||
target="_blank"
|
||||
class="flex items-center space-x-2 space-x-reverse px-4 py-2 bg-blue-700 text-white rounded-lg hover:bg-blue-800 transition-colors duration-200">
|
||||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
|
||||
</svg>
|
||||
<span>لینکدین</span>
|
||||
</a>
|
||||
<a href="https://t.me/share/url?url={{app.request.uri|url_encode}}&text={{item.title|url_encode}}"
|
||||
target="_blank"
|
||||
class="flex items-center space-x-2 space-x-reverse px-4 py-2 bg-blue-400 text-white rounded-lg hover:bg-blue-500 transition-colors duration-200">
|
||||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/>
|
||||
</svg>
|
||||
<span>تلگرام</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<!-- سایدبار -->
|
||||
<div class="lg:col-span-1">
|
||||
<div class="sticky top-8">
|
||||
<!-- پستهای مرتبط -->
|
||||
{% if posts|length > 0 %}
|
||||
<div class="bg-white rounded-2xl shadow-soft p-6 mb-8">
|
||||
<h3 class="text-xl font-bold text-gray-900 mb-6 flex items-center">
|
||||
<svg class="w-5 h-5 text-blue-600 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"></path>
|
||||
</svg>
|
||||
جدیدترینها
|
||||
</h3>
|
||||
<div class="space-y-4">
|
||||
{% for post in posts %}
|
||||
<a href="{{path('app_blog_post',{'url':post.url})}}"
|
||||
class="group block bg-gray-50 rounded-xl p-4 hover:bg-gray-100 transition-colors duration-200">
|
||||
<div class="flex space-x-3 space-x-reverse">
|
||||
<img src="{{asset('uploaded/'~ post.mainPic)}}"
|
||||
alt="{{post.title}}"
|
||||
class="w-16 h-16 object-cover rounded-lg flex-shrink-0">
|
||||
<div class="flex-1 min-w-0">
|
||||
<h4 class="text-sm font-semibold text-gray-900 group-hover:text-blue-600 transition-colors duration-200 line-clamp-2">
|
||||
{{post.title}}
|
||||
</h4>
|
||||
<p class="text-xs text-gray-500 mt-1">
|
||||
{{ Jdate.jdate('Y/n/d',post.dateSubmit) }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- دکمه بازگشت به وبلاگ -->
|
||||
<div class="bg-gradient-to-br from-blue-50 to-purple-50 rounded-2xl p-6 text-center">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">بازگشت به وبلاگ</h3>
|
||||
<p class="text-sm text-gray-600 mb-4">مطالب بیشتری را در وبلاگ ما بخوانید</p>
|
||||
<a href="{{path('app_blog_home')}}"
|
||||
class="inline-flex items-center space-x-2 space-x-reverse px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors duration-200 font-medium">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
|
||||
</svg>
|
||||
<span>مشاهده همه مطالب</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -15,15 +15,22 @@
|
|||
{{ item.plain | raw}}
|
||||
{% endif %}
|
||||
{% if item.body is not null %}
|
||||
<div class="container mt-3">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h1 class="text-primary py-4">{{item.title}}</h1>
|
||||
<main class="min-h-screen bg-gray-50">
|
||||
<div class="container mx-auto px-4 py-12">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<div class="bg-white rounded-2xl shadow-soft p-8 lg:p-12">
|
||||
<!-- عنوان صفحه -->
|
||||
<h1 class="text-3xl lg:text-4xl font-bold text-gray-900 mb-8 leading-tight">
|
||||
{{item.title}}
|
||||
</h1>
|
||||
|
||||
<!-- محتوای صفحه -->
|
||||
<div class="prose prose-lg max-w-none text-gray-800 leading-relaxed">
|
||||
{{ item.body | raw}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -3,55 +3,77 @@
|
|||
{% block title %}پرسیدن سوال جدید - پرسش و پاسخ{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container my-4">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="mb-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-2">
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
|
||||
<line x1="12" y1="17" x2="12.01" y2="17"></line>
|
||||
</svg>پرسیدن سوال جدید
|
||||
</h3>
|
||||
<main class="min-h-screen bg-gray-50">
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- هدر فرم -->
|
||||
<div class="text-center mb-8">
|
||||
<h1 class="text-3xl lg:text-4xl font-bold text-gray-900 mb-4">
|
||||
پرسیدن سوال جدید
|
||||
</h1>
|
||||
<p class="text-lg text-gray-600">
|
||||
سوال خود را مطرح کنید تا از تجربه دیگران استفاده کنید
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{ form_start(form, {'attr': {'novalidate': 'novalidate'}}) }}
|
||||
|
||||
<div class="mb-4">
|
||||
{{ form_label(form.title) }}
|
||||
{{ form_widget(form.title) }}
|
||||
<!-- فرم ایجاد سوال -->
|
||||
<div class="bg-white rounded-2xl shadow-soft overflow-hidden">
|
||||
<div class="p-8">
|
||||
{{ form_start(form, {'attr': {'novalidate': 'novalidate', 'class': 'space-y-8'}}) }}
|
||||
|
||||
<!-- عنوان سوال -->
|
||||
<div>
|
||||
<label for="{{ form.title.vars.id }}" class="block text-sm font-medium text-gray-700 mb-2">
|
||||
عنوان سوال
|
||||
</label>
|
||||
{{ form_widget(form.title, {'attr': {'class': 'w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200'}}) }}
|
||||
{{ form_errors(form.title) }}
|
||||
<div class="form-text">
|
||||
<p class="mt-2 text-sm text-gray-600">
|
||||
عنوان سوال باید واضح و مختصر باشد. سعی کنید مشکل خود را در یک جمله خلاصه کنید.
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
{{ form_label(form.content) }}
|
||||
<div class="editor-toolbar mb-2">
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="formatText('bold')" title="پررنگ">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"></path>
|
||||
<path d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"></path>
|
||||
<!-- محتوای سوال -->
|
||||
<div>
|
||||
<label for="{{ form.content.vars.id }}" class="block text-sm font-medium text-gray-700 mb-2">
|
||||
محتوای سوال
|
||||
</label>
|
||||
|
||||
<!-- نوار ابزار ادیتور -->
|
||||
<div class="flex flex-wrap gap-2 p-3 bg-gray-50 border border-gray-300 rounded-t-xl">
|
||||
<button type="button"
|
||||
onclick="formatText('bold')"
|
||||
title="پررنگ"
|
||||
class="p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-200 rounded-lg transition-colors duration-200">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="formatText('italic')" title="کج">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<button type="button"
|
||||
onclick="formatText('italic')"
|
||||
title="کج"
|
||||
class="p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-200 rounded-lg transition-colors duration-200">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<line x1="19" y1="4" x2="10" y2="4"></line>
|
||||
<line x1="14" y1="20" x2="5" y2="20"></line>
|
||||
<line x1="15" y1="4" x2="9" y2="20"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="formatText('code')" title="کد">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<button type="button"
|
||||
onclick="formatText('code')"
|
||||
title="کد"
|
||||
class="p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-200 rounded-lg transition-colors duration-200">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<polyline points="16,18 22,12 16,6"></polyline>
|
||||
<polyline points="8,6 2,12 8,18"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="insertList()" title="لیست">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<button type="button"
|
||||
onclick="insertList()"
|
||||
title="لیست"
|
||||
class="p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-200 rounded-lg transition-colors duration-200">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<line x1="8" y1="6" x2="21" y2="6"></line>
|
||||
<line x1="8" y1="12" x2="21" y2="12"></line>
|
||||
<line x1="8" y1="18" x2="21" y2="18"></line>
|
||||
|
|
@ -61,56 +83,115 @@
|
|||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{{ form_widget(form.content, {'attr': {'class': 'form-control editor-textarea', 'rows': 10}}) }}
|
||||
|
||||
{{ form_widget(form.content, {'attr': {'class': 'w-full px-4 py-3 border border-gray-300 border-t-0 rounded-b-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200', 'rows': 10}}) }}
|
||||
{{ form_errors(form.content) }}
|
||||
<div class="form-text">
|
||||
<p class="mt-2 text-sm text-gray-600">
|
||||
سوال خود را به تفصیل شرح دهید. هرچه جزئیات بیشتری ارائه دهید، پاسخهای بهتری دریافت خواهید کرد.
|
||||
<br><small class="text-muted">میتوانید از دکمههای بالا برای فرمت کردن متن استفاده کنید.</small>
|
||||
<br><span class="text-gray-500">میتوانید از دکمههای بالا برای فرمت کردن متن استفاده کنید.</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- تگها -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||
تگها
|
||||
<span class="text-red-500">*</span>
|
||||
</label>
|
||||
<div class="border border-gray-300 rounded-xl p-6 bg-gradient-to-br from-gray-50 to-blue-50">
|
||||
<!-- تگهای انتخاب شده -->
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<h4 class="text-sm font-semibold text-gray-700">تگهای انتخاب شده</h4>
|
||||
<span class="text-xs text-gray-500" id="tag-count">0 تگ انتخاب شده</span>
|
||||
</div>
|
||||
<div class="selected-tags min-h-12 flex flex-wrap gap-2 p-3 bg-white rounded-lg border-2 border-dashed border-gray-200" id="selected-tags">
|
||||
<div class="flex items-center text-gray-400 text-sm">
|
||||
<svg class="w-4 h-4 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
هیچ تگی انتخاب نشده است
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="form-label">تگها</label>
|
||||
<div class="tags-container">
|
||||
<div class="selected-tags mb-2" id="selected-tags"></div>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="tag-input" placeholder="تگ جدید را وارد کنید یا از لیست انتخاب کنید...">
|
||||
<button class="btn btn-outline-primary" type="button" id="add-tag-btn">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="12" y1="5" x2="12" y2="19"></line>
|
||||
<line x1="5" y1="12" x2="19" y2="12"></line>
|
||||
<!-- جستجو و افزودن تگ -->
|
||||
<div class="mb-6">
|
||||
<div class="relative">
|
||||
<input type="text"
|
||||
class="w-full px-4 py-3 pr-12 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 text-sm"
|
||||
id="tag-input"
|
||||
placeholder="نام تگ را تایپ کنید...">
|
||||
<button class="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600 transition-colors duration-200"
|
||||
type="button"
|
||||
id="search-icon">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="available-tags mt-2" id="available-tags">
|
||||
<small class="text-muted">تگهای موجود:</small>
|
||||
<div class="tag-suggestions mt-1">
|
||||
<div class="flex items-center justify-between mt-3">
|
||||
<button class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all duration-200 text-sm font-medium flex items-center space-x-2 space-x-reverse"
|
||||
type="button"
|
||||
id="add-tag-btn">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<line x1="12" y1="5" x2="12" y2="19"></line>
|
||||
<line x1="5" y1="12" x2="19" y2="12"></line>
|
||||
</svg>
|
||||
<span>افزودن تگ</span>
|
||||
</button>
|
||||
<span class="text-xs text-gray-500">حداقل 1 و حداکثر 5 تگ</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- تگهای پیشنهادی -->
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<h4 class="text-sm font-semibold text-gray-700">تگهای محبوب</h4>
|
||||
<button class="text-xs text-blue-600 hover:text-blue-800 transition-colors duration-200"
|
||||
type="button"
|
||||
id="show-all-tags">
|
||||
نمایش همه
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2" id="tag-suggestions">
|
||||
{% for tag in availableTags %}
|
||||
<span class="badge bg-light text-dark me-1 mb-1 tag-suggestion" data-tag-id="{{ tag.id }}" data-tag-name="{{ tag.name }}">
|
||||
<button type="button"
|
||||
class="inline-flex items-center px-3 py-2 bg-white text-gray-700 text-sm font-medium rounded-full border border-gray-300 hover:bg-blue-50 hover:border-blue-300 hover:text-blue-700 cursor-pointer transition-all duration-200 tag-suggestion"
|
||||
data-tag-id="{{ tag.id }}"
|
||||
data-tag-name="{{ tag.name }}">
|
||||
<svg class="w-3 h-3 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
{{ tag.name }}
|
||||
</span>
|
||||
</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-text">
|
||||
<p class="mt-2 text-sm text-gray-600">
|
||||
تگهای مرتبط را انتخاب کنید تا دیگران راحتتر بتوانند سوال شما را پیدا کنند.
|
||||
<br><small class="text-muted">میتوانید تگ جدید ایجاد کنید یا از تگهای موجود انتخاب کنید.</small>
|
||||
</div>
|
||||
<br><span class="text-gray-500">میتوانید تگ جدید ایجاد کنید یا از تگهای موجود انتخاب کنید.</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="{{ path('qa_index') }}" class="btn btn-outline-secondary">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-2">
|
||||
<path d="M19 12H5"></path>
|
||||
<!-- دکمههای فرم -->
|
||||
<div class="flex justify-between items-center pt-6 border-t border-gray-200">
|
||||
<a href="{{ path('qa_index') }}"
|
||||
class="inline-flex items-center space-x-2 space-x-reverse px-6 py-3 bg-gray-100 text-gray-700 rounded-xl hover:bg-gray-200 transition-all duration-200 font-medium">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 12H5"></path>
|
||||
<polyline points="12,19 5,12 12,5"></polyline>
|
||||
</svg>انصراف
|
||||
</svg>
|
||||
<span>انصراف</span>
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-2">
|
||||
<button type="submit"
|
||||
class="inline-flex items-center space-x-2 space-x-reverse px-8 py-3 bg-blue-600 text-white rounded-xl hover:bg-blue-700 transition-all duration-200 font-medium shadow-lg hover:shadow-xl transform hover:-translate-y-0.5">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<line x1="22" y1="2" x2="11" y2="13"></line>
|
||||
<polygon points="22,2 15,22 11,13 2,9 22,2"></polygon>
|
||||
</svg>ارسال سوال
|
||||
</svg>
|
||||
<span>ارسال سوال</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -119,36 +200,87 @@
|
|||
</div>
|
||||
|
||||
<!-- راهنمای پرسیدن سوال -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-2">
|
||||
<path d="M9 12l2 2 4-4"></path>
|
||||
<div class="bg-white rounded-2xl shadow-soft mt-8 overflow-hidden">
|
||||
<div class="bg-gradient-to-r from-blue-50 to-purple-50 px-8 py-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 flex items-center">
|
||||
<svg class="w-6 h-6 text-blue-600 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4"></path>
|
||||
<path d="M21 12c.552 0 1-.448 1-1s-.448-1-1-1-1 .448-1 1 .448 1 1 1z"></path>
|
||||
<path d="M3 12c.552 0 1-.448 1-1s-.448-1-1-1-1 .448-1 1 .448 1 1 1z"></path>
|
||||
<path d="M12 3c.552 0 1-.448 1-1s-.448-1-1-1-1 .448-1 1 .448 1 1 1z"></path>
|
||||
<path d="M12 21c.552 0 1-.448 1-1s-.448-1-1-1-1 .448-1 1 .448 1 1 1z"></path>
|
||||
</svg>راهنمای پرسیدن سوال خوب
|
||||
</h5>
|
||||
</svg>
|
||||
راهنمای پرسیدن سوال خوب
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-success">✅ کارهای درست:</h6>
|
||||
<ul class="list-unstyled">
|
||||
<li><i class="fas fa-check text-success me-2"></i>عنوان واضح و مختصر</li>
|
||||
<li><i class="fas fa-check text-success me-2"></i>شرح کامل مشکل</li>
|
||||
<li><i class="fas fa-check text-success me-2"></i>انتخاب تگهای مناسب</li>
|
||||
<li><i class="fas fa-check text-success me-2"></i>استفاده از کلمات کلیدی</li>
|
||||
<div class="p-8">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
<div>
|
||||
<h4 class="text-lg font-semibold text-green-700 mb-4 flex items-center">
|
||||
<svg class="w-5 h-5 text-green-600 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
کارهای درست
|
||||
</h4>
|
||||
<ul class="space-y-3">
|
||||
<li class="flex items-center space-x-3 space-x-reverse">
|
||||
<svg class="w-5 h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
<span class="text-gray-700">عنوان واضح و مختصر</span>
|
||||
</li>
|
||||
<li class="flex items-center space-x-3 space-x-reverse">
|
||||
<svg class="w-5 h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
<span class="text-gray-700">شرح کامل مشکل</span>
|
||||
</li>
|
||||
<li class="flex items-center space-x-3 space-x-reverse">
|
||||
<svg class="w-5 h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
<span class="text-gray-700">انتخاب تگهای مناسب</span>
|
||||
</li>
|
||||
<li class="flex items-center space-x-3 space-x-reverse">
|
||||
<svg class="w-5 h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
<span class="text-gray-700">استفاده از کلمات کلیدی</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-danger">❌ کارهای نادرست:</h6>
|
||||
<ul class="list-unstyled">
|
||||
<li><i class="fas fa-times text-danger me-2"></i>عنوان مبهم</li>
|
||||
<li><i class="fas fa-times text-danger me-2"></i>شرح ناکافی</li>
|
||||
<li><i class="fas fa-times text-danger me-2"></i>عدم انتخاب تگ</li>
|
||||
<li><i class="fas fa-times text-danger me-2"></i>سوال تکراری</li>
|
||||
<div>
|
||||
<h4 class="text-lg font-semibold text-red-700 mb-4 flex items-center">
|
||||
<svg class="w-5 h-5 text-red-600 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
کارهای نادرست
|
||||
</h4>
|
||||
<ul class="space-y-3">
|
||||
<li class="flex items-center space-x-3 space-x-reverse">
|
||||
<svg class="w-5 h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
<span class="text-gray-700">عنوان مبهم</span>
|
||||
</li>
|
||||
<li class="flex items-center space-x-3 space-x-reverse">
|
||||
<svg class="w-5 h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
<span class="text-gray-700">شرح ناکافی</span>
|
||||
</li>
|
||||
<li class="flex items-center space-x-3 space-x-reverse">
|
||||
<svg class="w-5 h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
<span class="text-gray-700">عدم انتخاب تگ</span>
|
||||
</li>
|
||||
<li class="flex items-center space-x-3 space-x-reverse">
|
||||
<svg class="w-5 h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
<span class="text-gray-700">سوال تکراری</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -156,232 +288,145 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
.form-control:focus, .form-select:focus {
|
||||
border-color: #0d6efd;
|
||||
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
||||
}
|
||||
|
||||
.card {
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
background-color: #f8f9fa;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.form-text {
|
||||
font-size: 0.9rem;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.list-unstyled li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.editor-toolbar {
|
||||
border: 1px solid #dee2e6;
|
||||
border-bottom: none;
|
||||
border-radius: 0.375rem 0.375rem 0 0;
|
||||
padding: 0.5rem;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.editor-textarea {
|
||||
border-radius: 0 0 0.375rem 0.375rem;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.tags-container {
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 0.375rem;
|
||||
padding: 1rem;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.selected-tags {
|
||||
min-height: 40px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tag-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
background-color: #0d6efd;
|
||||
color: white;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.tag-remove {
|
||||
background: none;
|
||||
border: none;
|
||||
color: white;
|
||||
margin-left: 0.5rem;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tag-suggestion {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.tag-suggestion:hover {
|
||||
background-color: #0d6efd !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.tag-suggestion.selected {
|
||||
background-color: #0d6efd !important;
|
||||
color: white !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
let selectedTags = [];
|
||||
// سیستم مدیریت تگها
|
||||
class TagManager {
|
||||
constructor() {
|
||||
this.selectedTags = [];
|
||||
this.maxTags = 5;
|
||||
this.minTags = 1;
|
||||
this.init();
|
||||
}
|
||||
|
||||
function initializeQuestionForm() {
|
||||
// ادیتور متن
|
||||
const textarea = document.querySelector('.editor-textarea');
|
||||
init() {
|
||||
this.tagInput = document.getElementById('tag-input');
|
||||
this.addTagBtn = document.getElementById('add-tag-btn');
|
||||
this.selectedTagsContainer = document.getElementById('selected-tags');
|
||||
this.tagSuggestions = document.querySelectorAll('.tag-suggestion');
|
||||
this.tagCount = document.getElementById('tag-count');
|
||||
this.showAllTagsBtn = document.getElementById('show-all-tags');
|
||||
|
||||
// سیستم تگها
|
||||
const tagInput = document.getElementById('tag-input');
|
||||
const addTagBtn = document.getElementById('add-tag-btn');
|
||||
const selectedTagsContainer = document.getElementById('selected-tags');
|
||||
const tagSuggestions = document.querySelectorAll('.tag-suggestion');
|
||||
|
||||
// اضافه کردن تگ
|
||||
function addTag(tagId, tagName) {
|
||||
if (selectedTags.find(tag => tag.id === tagId)) {
|
||||
if (!this.tagInput || !this.addTagBtn || !this.selectedTagsContainer) {
|
||||
console.error('Required elements not found for tag system');
|
||||
return;
|
||||
}
|
||||
|
||||
selectedTags.push({ id: tagId, name: tagName });
|
||||
renderSelectedTags();
|
||||
updateHiddenInput();
|
||||
console.log('Tag added:', { id: tagId, name: tagName });
|
||||
this.bindEvents();
|
||||
this.updateTagCount();
|
||||
this.renderSelectedTags();
|
||||
}
|
||||
|
||||
// حذف تگ
|
||||
window.removeTag = function(tagId) {
|
||||
selectedTags = selectedTags.filter(tag => tag.id !== tagId);
|
||||
renderSelectedTags();
|
||||
updateHiddenInput();
|
||||
}
|
||||
bindEvents() {
|
||||
// افزودن تگ با دکمه
|
||||
this.addTagBtn.addEventListener('click', () => this.addTagFromInput());
|
||||
|
||||
// نمایش تگهای انتخاب شده
|
||||
function renderSelectedTags() {
|
||||
selectedTagsContainer.innerHTML = '';
|
||||
selectedTags.forEach(tag => {
|
||||
const tagElement = document.createElement('span');
|
||||
tagElement.className = 'tag-item';
|
||||
tagElement.innerHTML = `
|
||||
${tag.name}
|
||||
<button type="button" class="tag-remove" data-tag-id="${tag.id}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
`;
|
||||
|
||||
// اضافه کردن event listener برای دکمه حذف
|
||||
const removeBtn = tagElement.querySelector('.tag-remove');
|
||||
removeBtn.addEventListener('click', function() {
|
||||
const tagId = this.dataset.tagId;
|
||||
window.removeTag(tagId);
|
||||
|
||||
// حذف کلاس selected از تگ پیشنهادی
|
||||
const suggestion = document.querySelector(`[data-tag-id="${tagId}"]`);
|
||||
if (suggestion) {
|
||||
suggestion.classList.remove('selected');
|
||||
// افزودن تگ با Enter
|
||||
this.tagInput.addEventListener('keypress', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
this.addTagFromInput();
|
||||
}
|
||||
});
|
||||
selectedTagsContainer.appendChild(tagElement);
|
||||
});
|
||||
}
|
||||
|
||||
// بهروزرسانی input مخفی
|
||||
function updateHiddenInput() {
|
||||
// حذف تمام input های قبلی
|
||||
const existingInputs = document.querySelectorAll('input[name="question[tags][]"]');
|
||||
existingInputs.forEach(input => input.remove());
|
||||
|
||||
// اضافه کردن input های جدید
|
||||
selectedTags.forEach(tag => {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'question[tags][]';
|
||||
input.value = tag.id;
|
||||
document.querySelector('form').appendChild(input);
|
||||
});
|
||||
|
||||
console.log('Selected tags:', selectedTags);
|
||||
}
|
||||
// جستجوی تگها
|
||||
this.tagInput.addEventListener('input', () => this.filterSuggestions());
|
||||
|
||||
// کلیک روی تگهای پیشنهادی
|
||||
tagSuggestions.forEach(suggestion => {
|
||||
suggestion.addEventListener('click', function() {
|
||||
const tagId = this.dataset.tagId;
|
||||
const tagName = this.dataset.tagName;
|
||||
this.tagSuggestions.forEach(suggestion => {
|
||||
suggestion.addEventListener('click', () => this.toggleTagSuggestion(suggestion));
|
||||
});
|
||||
|
||||
if (selectedTags.find(tag => tag.id === tagId)) {
|
||||
window.removeTag(tagId);
|
||||
this.classList.remove('selected');
|
||||
} else {
|
||||
addTag(tagId, tagName);
|
||||
this.classList.add('selected');
|
||||
// نمایش همه تگها
|
||||
if (this.showAllTagsBtn) {
|
||||
this.showAllTagsBtn.addEventListener('click', () => this.showAllTags());
|
||||
}
|
||||
}
|
||||
|
||||
addTag(tagId, tagName) {
|
||||
// بررسی محدودیت تعداد تگها
|
||||
if (this.selectedTags.length >= this.maxTags) {
|
||||
if (window.notification) {
|
||||
window.notification.warning(`حداکثر ${this.maxTags} تگ میتوانید انتخاب کنید`);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// اضافه کردن تگ جدید
|
||||
addTagBtn.addEventListener('click', function() {
|
||||
const tagName = tagInput.value.trim();
|
||||
if (tagName) {
|
||||
// بررسی وجود تگ
|
||||
const existingTag = Array.from(tagSuggestions).find(suggestion =>
|
||||
if (this.selectedTags.find(tag => tag.id === tagId)) {
|
||||
if (window.notification) {
|
||||
window.notification.info('این تگ قبلاً انتخاب شده است');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
this.selectedTags.push({ id: tagId, name: tagName });
|
||||
this.updateTagCount();
|
||||
this.renderSelectedTags();
|
||||
this.updateHiddenInput();
|
||||
this.updateSuggestionState(tagId, true);
|
||||
|
||||
if (window.notification) {
|
||||
window.notification.success(`تگ "${tagName}" اضافه شد`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
removeTag(tagId) {
|
||||
const tagIndex = this.selectedTags.findIndex(tag => tag.id === tagId);
|
||||
if (tagIndex === -1) return false;
|
||||
|
||||
const removedTag = this.selectedTags[tagIndex];
|
||||
this.selectedTags.splice(tagIndex, 1);
|
||||
|
||||
this.updateTagCount();
|
||||
this.renderSelectedTags();
|
||||
this.updateHiddenInput();
|
||||
this.updateSuggestionState(tagId, false);
|
||||
|
||||
if (window.notification) {
|
||||
window.notification.info(`تگ "${removedTag.name}" حذف شد`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
addTagFromInput() {
|
||||
const tagName = this.tagInput.value.trim();
|
||||
|
||||
if (!tagName) {
|
||||
if (window.notification) {
|
||||
window.notification.warning('لطفاً نام تگ را وارد کنید');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// بررسی تگ موجود
|
||||
const existingTag = Array.from(this.tagSuggestions).find(suggestion =>
|
||||
suggestion.dataset.tagName.toLowerCase() === tagName.toLowerCase()
|
||||
);
|
||||
|
||||
if (existingTag) {
|
||||
const tagId = existingTag.dataset.tagId;
|
||||
const tagName = existingTag.dataset.tagName;
|
||||
addTag(tagId, tagName);
|
||||
existingTag.classList.add('selected');
|
||||
} else {
|
||||
// ایجاد تگ جدید
|
||||
createNewTag(tagName);
|
||||
this.addTag(tagId, tagName);
|
||||
this.tagInput.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
tagInput.value = '';
|
||||
}
|
||||
});
|
||||
|
||||
// Enter برای اضافه کردن تگ
|
||||
tagInput.addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
addTagBtn.click();
|
||||
}
|
||||
});
|
||||
|
||||
// ایجاد تگ جدید
|
||||
function createNewTag(tagName) {
|
||||
this.createNewTag(tagName);
|
||||
}
|
||||
|
||||
createNewTag(tagName) {
|
||||
// نمایش حالت بارگذاری
|
||||
const originalContent = this.addTagBtn.innerHTML;
|
||||
this.addTagBtn.innerHTML = '<div class="loading-spinner"></div>';
|
||||
this.addTagBtn.disabled = true;
|
||||
|
||||
fetch('/qa/tag/create', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
|
@ -393,44 +438,184 @@ function initializeQuestionForm() {
|
|||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
alert(data.error);
|
||||
if (window.notification) {
|
||||
window.notification.error(data.error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// اضافه کردن تگ به لیست انتخاب شده
|
||||
addTag(data.id, data.name);
|
||||
// افزودن تگ جدید
|
||||
if (this.addTag(data.id, data.name)) {
|
||||
this.tagInput.value = '';
|
||||
|
||||
// اضافه کردن تگ به لیست پیشنهادی
|
||||
const suggestionElement = document.createElement('span');
|
||||
suggestionElement.className = 'badge bg-light text-dark me-1 mb-1 tag-suggestion selected';
|
||||
suggestionElement.dataset.tagId = data.id;
|
||||
suggestionElement.dataset.tagName = data.name;
|
||||
suggestionElement.textContent = data.name;
|
||||
suggestionElement.addEventListener('click', function() {
|
||||
if (selectedTags.find(tag => tag.id === data.id)) {
|
||||
removeTag(data.id);
|
||||
this.classList.remove('selected');
|
||||
} else {
|
||||
addTag(data.id, data.name);
|
||||
this.classList.add('selected');
|
||||
// افزودن به لیست پیشنهادی
|
||||
this.addToSuggestions(data.id, data.name);
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelector('.tag-suggestions').appendChild(suggestionElement);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('خطا در ایجاد تگ جدید');
|
||||
console.error('Error creating tag:', error);
|
||||
if (window.notification) {
|
||||
window.notification.error('خطا در ایجاد تگ جدید. لطفاً دوباره تلاش کنید.');
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
// بازگردانی دکمه
|
||||
this.addTagBtn.innerHTML = originalContent;
|
||||
this.addTagBtn.disabled = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// توابع ادیتور متن
|
||||
function formatText(command) {
|
||||
const textarea = document.querySelector('.editor-textarea');
|
||||
const start = textarea.selectionStart;
|
||||
const end = textarea.selectionEnd;
|
||||
const selectedText = textarea.value.substring(start, end);
|
||||
addToSuggestions(tagId, tagName) {
|
||||
const suggestionElement = document.createElement('button');
|
||||
suggestionElement.type = 'button';
|
||||
suggestionElement.className = 'inline-flex items-center px-3 py-2 bg-white text-gray-700 text-sm font-medium rounded-full border border-gray-300 hover:bg-blue-50 hover:border-blue-300 hover:text-blue-700 cursor-pointer transition-all duration-200 tag-suggestion';
|
||||
suggestionElement.dataset.tagId = tagId;
|
||||
suggestionElement.dataset.tagName = tagName;
|
||||
suggestionElement.innerHTML = `
|
||||
<svg class="w-3 h-3 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
${tagName}
|
||||
`;
|
||||
|
||||
suggestionElement.addEventListener('click', () => this.toggleTagSuggestion(suggestionElement));
|
||||
|
||||
const container = document.getElementById('tag-suggestions');
|
||||
if (container) {
|
||||
container.appendChild(suggestionElement);
|
||||
this.tagSuggestions = document.querySelectorAll('.tag-suggestion');
|
||||
}
|
||||
}
|
||||
|
||||
toggleTagSuggestion(suggestion) {
|
||||
const tagId = suggestion.dataset.tagId;
|
||||
const tagName = suggestion.dataset.tagName;
|
||||
|
||||
if (this.selectedTags.find(tag => tag.id === tagId)) {
|
||||
this.removeTag(tagId);
|
||||
} else {
|
||||
this.addTag(tagId, tagName);
|
||||
}
|
||||
}
|
||||
|
||||
updateSuggestionState(tagId, isSelected) {
|
||||
const suggestion = document.querySelector(`[data-tag-id="${tagId}"]`);
|
||||
if (!suggestion) return;
|
||||
|
||||
if (isSelected) {
|
||||
suggestion.classList.remove('bg-white', 'text-gray-700', 'border-gray-300');
|
||||
suggestion.classList.add('bg-blue-600', 'text-white', 'border-blue-600');
|
||||
} else {
|
||||
suggestion.classList.remove('bg-blue-600', 'text-white', 'border-blue-600');
|
||||
suggestion.classList.add('bg-white', 'text-gray-700', 'border-gray-300');
|
||||
}
|
||||
}
|
||||
|
||||
renderSelectedTags() {
|
||||
this.selectedTagsContainer.innerHTML = '';
|
||||
|
||||
if (this.selectedTags.length === 0) {
|
||||
this.selectedTagsContainer.innerHTML = `
|
||||
<div class="flex items-center text-gray-400 text-sm">
|
||||
<svg class="w-4 h-4 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
هیچ تگی انتخاب نشده است
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectedTags.forEach(tag => {
|
||||
const tagElement = document.createElement('div');
|
||||
tagElement.className = 'inline-flex items-center px-3 py-2 bg-blue-600 text-white text-sm font-medium rounded-full shadow-sm';
|
||||
tagElement.innerHTML = `
|
||||
<svg class="w-3 h-3 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path>
|
||||
</svg>
|
||||
${tag.name}
|
||||
<button type="button"
|
||||
class="tag-remove mr-2 text-white hover:text-red-200 transition-colors duration-200"
|
||||
data-tag-id="${tag.id}">
|
||||
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
`;
|
||||
|
||||
// رویداد حذف تگ
|
||||
const removeBtn = tagElement.querySelector('.tag-remove');
|
||||
removeBtn.addEventListener('click', () => this.removeTag(tag.id));
|
||||
|
||||
this.selectedTagsContainer.appendChild(tagElement);
|
||||
});
|
||||
}
|
||||
|
||||
updateTagCount() {
|
||||
if (this.tagCount) {
|
||||
this.tagCount.textContent = `${this.selectedTags.length} تگ انتخاب شده`;
|
||||
}
|
||||
}
|
||||
|
||||
updateHiddenInput() {
|
||||
// حذف input های قبلی
|
||||
const existingInputs = document.querySelectorAll('input[name="question[tags][]"]');
|
||||
existingInputs.forEach(input => input.remove());
|
||||
|
||||
// افزودن input های جدید
|
||||
this.selectedTags.forEach(tag => {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'question[tags][]';
|
||||
input.value = tag.id;
|
||||
document.querySelector('form').appendChild(input);
|
||||
});
|
||||
}
|
||||
|
||||
filterSuggestions() {
|
||||
const searchTerm = this.tagInput.value.toLowerCase();
|
||||
|
||||
this.tagSuggestions.forEach(suggestion => {
|
||||
const tagName = suggestion.dataset.tagName.toLowerCase();
|
||||
if (tagName.includes(searchTerm)) {
|
||||
suggestion.style.display = 'inline-flex';
|
||||
} else {
|
||||
suggestion.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
showAllTags() {
|
||||
this.tagSuggestions.forEach(suggestion => {
|
||||
suggestion.style.display = 'inline-flex';
|
||||
});
|
||||
this.tagInput.value = '';
|
||||
}
|
||||
|
||||
validateTags() {
|
||||
if (this.selectedTags.length < this.minTags) {
|
||||
if (window.notification) {
|
||||
window.notification.error(`حداقل ${this.minTags} تگ باید انتخاب کنید`);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// ادیتور متن
|
||||
class TextEditor {
|
||||
constructor() {
|
||||
this.textarea = document.querySelector('textarea[name="question[content]"]');
|
||||
}
|
||||
|
||||
formatText(command) {
|
||||
if (!this.textarea) return;
|
||||
|
||||
const start = this.textarea.selectionStart;
|
||||
const end = this.textarea.selectionEnd;
|
||||
const selectedText = this.textarea.value.substring(start, end);
|
||||
|
||||
let formattedText = '';
|
||||
|
||||
|
|
@ -446,23 +631,64 @@ function formatText(command) {
|
|||
break;
|
||||
}
|
||||
|
||||
textarea.value = textarea.value.substring(0, start) + formattedText + textarea.value.substring(end);
|
||||
textarea.focus();
|
||||
textarea.setSelectionRange(start + formattedText.length, start + formattedText.length);
|
||||
this.textarea.value = this.textarea.value.substring(0, start) + formattedText + this.textarea.value.substring(end);
|
||||
this.textarea.focus();
|
||||
this.textarea.setSelectionRange(start + formattedText.length, start + formattedText.length);
|
||||
}
|
||||
|
||||
function insertList() {
|
||||
const textarea = document.querySelector('.editor-textarea');
|
||||
const start = textarea.selectionStart;
|
||||
const end = textarea.selectionEnd;
|
||||
const selectedText = textarea.value.substring(start, end);
|
||||
insertList() {
|
||||
if (!this.textarea) return;
|
||||
|
||||
const start = this.textarea.selectionStart;
|
||||
const end = this.textarea.selectionEnd;
|
||||
const selectedText = this.textarea.value.substring(start, end);
|
||||
|
||||
const listText = selectedText.split('\n').map(line => `- ${line}`).join('\n');
|
||||
textarea.value = textarea.value.substring(0, start) + listText + textarea.value.substring(end);
|
||||
textarea.focus();
|
||||
this.textarea.value = this.textarea.value.substring(0, start) + listText + this.textarea.value.substring(end);
|
||||
this.textarea.focus();
|
||||
}
|
||||
}
|
||||
|
||||
// اجرا در هر دو حالت
|
||||
// متغیرهای سراسری
|
||||
let tagManager;
|
||||
let textEditor;
|
||||
|
||||
// توابع سراسری برای HTML
|
||||
window.formatText = function(command) {
|
||||
if (textEditor) {
|
||||
textEditor.formatText(command);
|
||||
}
|
||||
};
|
||||
|
||||
window.insertList = function() {
|
||||
if (textEditor) {
|
||||
textEditor.insertList();
|
||||
}
|
||||
};
|
||||
|
||||
// مقداردهی اولیه
|
||||
function initializeQuestionForm() {
|
||||
if (typeof window.notification === 'undefined') {
|
||||
setTimeout(initializeQuestionForm, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
tagManager = new TagManager();
|
||||
textEditor = new TextEditor();
|
||||
|
||||
// اعتبارسنجی فرم
|
||||
const form = document.querySelector('form');
|
||||
if (form) {
|
||||
form.addEventListener('submit', function(e) {
|
||||
if (!tagManager.validateTags()) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// اجرا در بارگذاری صفحه
|
||||
document.addEventListener('DOMContentLoaded', initializeQuestionForm);
|
||||
document.addEventListener('turbo:load', initializeQuestionForm);
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -3,111 +3,153 @@
|
|||
{% block title %}پرسش و پاسخ - حسابیکس{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container my-4">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="text-primary fw-bold">پرسش و پاسخ</h1>
|
||||
<main class="min-h-screen bg-gray-50">
|
||||
<!-- هدر Q&A -->
|
||||
<div class="bg-gradient-to-br from-blue-600 via-purple-600 to-indigo-700">
|
||||
<div class="container mx-auto px-4 py-12">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<div class="flex flex-col lg:flex-row lg:items-center lg:justify-between">
|
||||
<div class="text-white mb-6 lg:mb-0">
|
||||
<h1 class="text-4xl lg:text-5xl font-bold mb-4 animate-fade-in-up">
|
||||
پرسش و پاسخ
|
||||
</h1>
|
||||
<p class="text-lg text-blue-100 animate-fade-in-up" style="animation-delay: 0.2s;">
|
||||
سوالات خود را بپرسید و از تجربه دیگران استفاده کنید
|
||||
</p>
|
||||
</div>
|
||||
<div class="animate-fade-in-up" style="animation-delay: 0.4s;">
|
||||
{% if app.user and 'ROLE_CUSTOMER' in app.user.roles %}
|
||||
<a href="{{ path('qa_ask') }}" class="btn btn-primary">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-2">
|
||||
<a href="{{ path('qa_ask') }}"
|
||||
class="inline-flex items-center space-x-2 space-x-reverse px-6 py-3 bg-white text-blue-600 rounded-xl hover:bg-blue-50 transition-all duration-200 font-medium shadow-lg hover:shadow-xl transform hover:-translate-y-1">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<line x1="12" y1="5" x2="12" y2="19"></line>
|
||||
<line x1="5" y1="12" x2="19" y2="12"></line>
|
||||
</svg>سوال جدید
|
||||
</svg>
|
||||
<span>سوال جدید</span>
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{{ path('customer_login') }}" class="btn btn-outline-primary">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-2">
|
||||
<a href="{{ path('customer_login') }}"
|
||||
class="inline-flex items-center space-x-2 space-x-reverse px-6 py-3 bg-blue-500 text-white rounded-xl hover:bg-blue-600 transition-all duration-200 font-medium shadow-lg hover:shadow-xl transform hover:-translate-y-1">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path>
|
||||
<polyline points="10,17 15,12 10,7"></polyline>
|
||||
<line x1="15" y1="12" x2="3" y2="12"></line>
|
||||
</svg>ورود برای پرسیدن سوال
|
||||
</svg>
|
||||
<span>ورود برای پرسیدن سوال</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- محتوای اصلی -->
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-4 gap-8">
|
||||
<!-- محتوای اصلی -->
|
||||
<div class="lg:col-span-3">
|
||||
|
||||
<!-- فیلترها و جستجو -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<form method="GET" class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<label for="filter" class="form-label">فیلتر:</label>
|
||||
<select name="filter" id="filter" class="form-select">
|
||||
<div class="bg-white rounded-2xl shadow-soft p-6 mb-8">
|
||||
<form method="GET" class="space-y-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label for="filter" class="block text-sm font-medium text-gray-700 mb-2">فیلتر:</label>
|
||||
<select name="filter" id="filter"
|
||||
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200">
|
||||
<option value="all" {{ currentFilter == 'all' ? 'selected' : '' }}>همه سوالات</option>
|
||||
<option value="unsolved" {{ currentFilter == 'unsolved' ? 'selected' : '' }}>سوالات حل نشده</option>
|
||||
<option value="solved" {{ currentFilter == 'solved' ? 'selected' : '' }}>سوالات حل شده</option>
|
||||
<option value="popular" {{ currentFilter == 'popular' ? 'selected' : '' }}>محبوبترین</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="search" class="form-label">جستجو:</label>
|
||||
<input type="text" name="search" id="search" class="form-control"
|
||||
<div>
|
||||
<label for="search" class="block text-sm font-medium text-gray-700 mb-2">جستجو:</label>
|
||||
<input type="text" name="search" id="search"
|
||||
class="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200"
|
||||
value="{{ currentSearch }}" placeholder="جستجو در سوالات...">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label"> </label>
|
||||
<button type="submit" class="btn btn-primary w-100">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-1">
|
||||
<div class="flex items-end">
|
||||
<button type="submit"
|
||||
class="w-full px-6 py-3 bg-blue-600 text-white rounded-xl hover:bg-blue-700 transition-all duration-200 font-medium shadow-lg hover:shadow-xl transform hover:-translate-y-0.5">
|
||||
<div class="flex items-center justify-center space-x-2 space-x-reverse">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<circle cx="11" cy="11" r="8"></circle>
|
||||
<path d="m21 21-4.35-4.35"></path>
|
||||
</svg>جستجو
|
||||
</svg>
|
||||
<span>جستجو</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- لیست سوالات -->
|
||||
<div class="col-lg-9">
|
||||
{% if questions is empty %}
|
||||
<div class="card">
|
||||
<div class="card-body text-center py-5">
|
||||
<i class="fas fa-question-circle fa-3x text-muted mb-3"></i>
|
||||
<h4 class="text-muted">سوالی یافت نشد</h4>
|
||||
<p class="text-muted">هنوز سوالی در این دستهبندی وجود ندارد.</p>
|
||||
<div class="bg-white rounded-2xl shadow-soft p-12 text-center">
|
||||
<div class="max-w-md mx-auto">
|
||||
<svg class="w-16 h-16 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">سوالی یافت نشد</h3>
|
||||
<p class="text-gray-600 mb-6">هنوز سوالی در این دستهبندی وجود ندارد.</p>
|
||||
{% if app.user and 'ROLE_CUSTOMER' in app.user.roles %}
|
||||
<a href="{{ path('qa_ask') }}" class="btn btn-primary">اولین سوال را بپرسید</a>
|
||||
<a href="{{ path('qa_ask') }}"
|
||||
class="inline-flex items-center space-x-2 space-x-reverse px-6 py-3 bg-blue-600 text-white rounded-xl hover:bg-blue-700 transition-all duration-200 font-medium shadow-lg hover:shadow-xl transform hover:-translate-y-0.5">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<line x1="12" y1="5" x2="12" y2="19"></line>
|
||||
<line x1="5" y1="12" x2="19" y2="12"></line>
|
||||
</svg>
|
||||
<span>اولین سوال را بپرسید</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="space-y-6">
|
||||
{% for question in questions %}
|
||||
<div class="card mb-3 question-card">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-2 col-md-1 text-center">
|
||||
<div class="d-flex flex-column align-items-center">
|
||||
<div class="vote-count {{ question.votes > 0 ? 'text-success' : (question.votes < 0 ? 'text-danger' : 'text-muted') }}">
|
||||
<div class="bg-white rounded-2xl shadow-soft hover:shadow-medium transition-all duration-300 overflow-hidden hover-lift group">
|
||||
<div class="p-6">
|
||||
<div class="flex space-x-4 space-x-reverse">
|
||||
<!-- آمار سوال -->
|
||||
<div class="flex flex-col items-center space-y-2 min-w-0">
|
||||
<div class="text-center">
|
||||
<div class="text-2xl font-bold {{ question.votes > 0 ? 'text-green-600' : (question.votes < 0 ? 'text-red-600' : 'text-gray-500') }}">
|
||||
{{ question.votes }}
|
||||
</div>
|
||||
<small class="text-muted">رای</small>
|
||||
<div class="text-xs text-gray-500">رای</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2 col-md-1 text-center">
|
||||
<div class="d-flex flex-column align-items-center">
|
||||
<div class="answer-count {{ question.answers|length > 0 ? 'text-success' : 'text-muted' }}">
|
||||
<div class="text-center">
|
||||
<div class="text-lg font-semibold {{ question.answers|length > 0 ? 'text-green-600' : 'text-gray-500' }}">
|
||||
{{ question.answers|length }}
|
||||
</div>
|
||||
<small class="text-muted">پاسخ</small>
|
||||
<div class="text-xs text-gray-500">پاسخ</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-8 col-md-10">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
<h5 class="card-title mb-0">
|
||||
|
||||
<!-- محتوای سوال -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-start justify-between mb-3">
|
||||
<h3 class="text-lg font-semibold text-gray-900 group-hover:text-blue-600 transition-colors duration-200">
|
||||
<a href="{{ path('qa_question_show', {'id': question.id}) }}"
|
||||
class="text-decoration-none text-dark">
|
||||
class="hover:underline">
|
||||
{{ question.title }}
|
||||
</a>
|
||||
</h5>
|
||||
</h3>
|
||||
{% if question.isSolved %}
|
||||
<span class="badge bg-success">
|
||||
<i class="fas fa-check me-1"></i>حل شده
|
||||
<span class="inline-flex items-center space-x-1 space-x-reverse px-3 py-1 bg-green-100 text-green-800 text-sm font-medium rounded-full">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
<span>حل شده</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="card-text text-muted mb-2 question-preview">
|
||||
<div class="text-gray-600 mb-4 line-clamp-3 leading-relaxed">
|
||||
{% set content = question.content|markdown|raw %}
|
||||
{% set plainText = content|striptags %}
|
||||
{% if plainText|length > 200 %}
|
||||
|
|
@ -117,19 +159,38 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="tags">
|
||||
<div class="flex flex-wrap items-center justify-between gap-4">
|
||||
<!-- تگها -->
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{% for tagRelation in question.tagRelations %}
|
||||
<a href="{{ path('qa_tag_questions', {'name': tagRelation.tag.name}) }}"
|
||||
class="badge bg-light text-dark text-decoration-none me-1">
|
||||
class="inline-flex items-center px-3 py-1 bg-blue-100 text-blue-800 text-sm font-medium rounded-full hover:bg-blue-200 transition-colors duration-200">
|
||||
{{ tagRelation.tag.name }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="text-muted small">
|
||||
<i class="fas fa-user me-1"></i>{{ question.author.name }}
|
||||
<i class="fas fa-clock ms-3 me-1"></i>{{ question.createdAt|date('Y/m/d H:i') }}
|
||||
<i class="fas fa-eye ms-3 me-1"></i>{{ question.views }}
|
||||
|
||||
<!-- اطلاعات سوال -->
|
||||
<div class="flex items-center space-x-4 space-x-reverse text-sm text-gray-500">
|
||||
<div class="flex items-center space-x-1 space-x-reverse">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
|
||||
</svg>
|
||||
<span>{{ question.author.name }}</span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-1 space-x-reverse">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<span>{{ question.createdAt|date('Y/m/d H:i') }}</span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-1 space-x-reverse">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
|
||||
</svg>
|
||||
<span>{{ question.views }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -137,89 +198,104 @@
|
|||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- صفحهبندی -->
|
||||
{% if totalPages > 1 %}
|
||||
<nav aria-label="صفحهبندی سوالات">
|
||||
<ul class="pagination justify-content-center">
|
||||
<div class="mt-8">
|
||||
<nav class="flex justify-center" aria-label="صفحهبندی سوالات">
|
||||
<div class="flex items-center space-x-2 space-x-reverse">
|
||||
<!-- دکمه صفحه قبل -->
|
||||
{% if currentPage > 1 %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ currentPage - 1 }}{{ currentFilter != 'all' ? '&filter=' ~ currentFilter : '' }}{{ currentSearch ? '&search=' ~ currentSearch : '' }}{{ currentTag ? '&tag=' ~ currentTag : '' }}">قبلی</a>
|
||||
</li>
|
||||
<a href="?page={{ currentPage - 1 }}{{ currentFilter != 'all' ? '&filter=' ~ currentFilter : '' }}{{ currentSearch ? '&search=' ~ currentSearch : '' }}{{ currentTag ? '&tag=' ~ currentTag : '' }}"
|
||||
class="flex items-center space-x-2 space-x-reverse px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 hover:text-gray-700 transition-all duration-200">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
<span>قبلی</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<!-- شماره صفحات -->
|
||||
<div class="flex items-center space-x-1 space-x-reverse">
|
||||
{% for page in 1..totalPages %}
|
||||
{% if page == currentPage %}
|
||||
<li class="page-item active">
|
||||
<span class="page-link">{{ page }}</span>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page }}{{ currentFilter != 'all' ? '&filter=' ~ currentFilter : '' }}{{ currentSearch ? '&search=' ~ currentSearch : '' }}{{ currentTag ? '&tag=' ~ currentTag : '' }}">{{ page }}</a>
|
||||
</li>
|
||||
<span class="px-4 py-2 text-sm font-medium text-white bg-blue-600 border border-blue-600 rounded-lg">
|
||||
{{ page }}
|
||||
</span>
|
||||
{% elseif page <= currentPage + 2 and page >= currentPage - 2 %}
|
||||
<a href="?page={{ page }}{{ currentFilter != 'all' ? '&filter=' ~ currentFilter : '' }}{{ currentSearch ? '&search=' ~ currentSearch : '' }}{{ currentTag ? '&tag=' ~ currentTag : '' }}"
|
||||
class="px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 hover:text-gray-700 transition-all duration-200">
|
||||
{{ page }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- دکمه صفحه بعد -->
|
||||
{% if currentPage < totalPages %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ currentPage + 1 }}{{ currentFilter != 'all' ? '&filter=' ~ currentFilter : '' }}{{ currentSearch ? '&search=' ~ currentSearch : '' }}{{ currentTag ? '&tag=' ~ currentTag : '' }}">بعدی</a>
|
||||
</li>
|
||||
<a href="?page={{ currentPage + 1 }}{{ currentFilter != 'all' ? '&filter=' ~ currentFilter : '' }}{{ currentSearch ? '&search=' ~ currentSearch : '' }}{{ currentTag ? '&tag=' ~ currentTag : '' }}"
|
||||
class="flex items-center space-x-2 space-x-reverse px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 hover:text-gray-700 transition-all duration-200">
|
||||
<span>بعدی</span>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
|
||||
</svg>
|
||||
</a>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- سایدبار -->
|
||||
<div class="col-lg-3">
|
||||
<div class="lg:col-span-1">
|
||||
<div class="space-y-6">
|
||||
<!-- تگهای محبوب -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-2">
|
||||
<path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"></path>
|
||||
<line x1="7" y1="7" x2="7.01" y2="7"></line>
|
||||
</svg>تگهای محبوب
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="bg-white rounded-2xl shadow-soft p-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-4 flex items-center">
|
||||
<svg class="w-5 h-5 text-blue-600 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path>
|
||||
</svg>
|
||||
تگهای محبوب
|
||||
</h3>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{% for tag in popularTags %}
|
||||
<a href="{{ path('qa_tag_questions', {'name': tag.name}) }}"
|
||||
class="badge bg-light text-dark text-decoration-none me-1 mb-2 d-inline-block">
|
||||
class="inline-flex items-center px-3 py-1 bg-blue-100 text-blue-800 text-sm font-medium rounded-full hover:bg-blue-200 transition-colors duration-200">
|
||||
{{ tag.name }}
|
||||
<span class="text-muted">({{ tag.usageCount }})</span>
|
||||
<span class="text-blue-600 mr-1">({{ tag.usageCount }})</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
<div class="mt-3">
|
||||
<a href="{{ path('qa_tags') }}" class="btn btn-outline-primary btn-sm">
|
||||
مشاهده همه تگها
|
||||
</a>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<a href="{{ path('qa_tags') }}"
|
||||
class="inline-flex items-center space-x-2 space-x-reverse text-blue-600 hover:text-blue-700 font-medium transition-colors duration-200">
|
||||
<span>مشاهده همه تگها</span>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- آمار -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-2">
|
||||
<path d="M18 20V10"></path>
|
||||
<path d="M12 20V4"></path>
|
||||
<path d="M6 20v-6"></path>
|
||||
</svg>آمار
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row text-center">
|
||||
<div class="col-6">
|
||||
<div class="h4 text-primary">{{ questions|length }}</div>
|
||||
<small class="text-muted">سوال</small>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="h4 text-success">{{ popularTags|length }}</div>
|
||||
<small class="text-muted">تگ</small>
|
||||
<div class="bg-gradient-to-br from-blue-50 to-purple-50 rounded-2xl p-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-4 flex items-center">
|
||||
<svg class="w-5 h-5 text-blue-600 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
|
||||
</svg>
|
||||
آمار
|
||||
</h3>
|
||||
<div class="grid grid-cols-2 gap-4 text-center">
|
||||
<div>
|
||||
<div class="text-2xl font-bold text-blue-600">{{ questions|length }}</div>
|
||||
<div class="text-sm text-gray-600">سوال</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-2xl font-bold text-green-600">{{ popularTags|length }}</div>
|
||||
<div class="text-sm text-gray-600">تگ</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -228,79 +304,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
.question-card {
|
||||
transition: all 0.3s ease;
|
||||
border-left: 4px solid transparent;
|
||||
}
|
||||
|
||||
.question-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
border-left-color: #0d6efd;
|
||||
}
|
||||
|
||||
.vote-count, .answer-count {
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tags .badge {
|
||||
font-size: 0.8rem;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.tags .badge:hover {
|
||||
background-color: #0d6efd !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.card-title a:hover {
|
||||
color: #0d6efd !important;
|
||||
}
|
||||
|
||||
.question-preview {
|
||||
line-height: 1.6;
|
||||
max-height: 4.8em; /* حدود 3 خط */
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.question-card {
|
||||
transition: all 0.3s ease;
|
||||
border-left: 4px solid transparent;
|
||||
}
|
||||
|
||||
.question-card:hover {
|
||||
border-left-color: #0d6efd;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.question-stats {
|
||||
font-size: 0.9rem;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.question-stats .stat-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.question-stats .stat-number {
|
||||
font-weight: bold;
|
||||
font-size: 1.1rem;
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.question-stats .stat-label {
|
||||
font-size: 0.8rem;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -3,65 +3,88 @@
|
|||
{% block title %}{{ question.title }} - پرسش و پاسخ{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container my-4">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<main class="min-h-screen bg-gray-50">
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<!-- سوال -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-1 text-center">
|
||||
<div class="vote-section">
|
||||
<button class="btn btn-outline-success btn-sm vote-btn"
|
||||
<div class="bg-white rounded-2xl shadow-soft mb-8 overflow-hidden">
|
||||
<div class="p-8">
|
||||
<div class="flex space-x-6 space-x-reverse">
|
||||
<!-- سیستم رایدهی -->
|
||||
<div class="flex flex-col items-center space-y-2 min-w-0">
|
||||
<button class="vote-btn w-10 h-10 flex items-center justify-center rounded-lg border-2 border-green-200 text-green-600 hover:bg-green-50 hover:border-green-300 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
data-type="question"
|
||||
data-id="{{ question.id }}"
|
||||
data-upvote="true"
|
||||
{% if not app.user or 'ROLE_CUSTOMER' not in app.user.roles %}disabled{% endif %}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="18,15 12,9 6,15"></polyline>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="vote-count mt-2 mb-2" id="question-votes-{{ question.id }}">
|
||||
<div class="text-2xl font-bold text-gray-900" id="question-votes-{{ question.id }}">
|
||||
{{ question.votes }}
|
||||
</div>
|
||||
<button class="btn btn-outline-danger btn-sm vote-btn"
|
||||
<button class="vote-btn w-10 h-10 flex items-center justify-center rounded-lg border-2 border-red-200 text-red-600 hover:bg-red-50 hover:border-red-300 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
data-type="question"
|
||||
data-id="{{ question.id }}"
|
||||
data-upvote="false"
|
||||
{% if not app.user or 'ROLE_CUSTOMER' not in app.user.roles %}disabled{% endif %}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="6,9 12,15 18,9"></polyline>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-11">
|
||||
<div class="d-flex justify-content-between align-items-start mb-3">
|
||||
<h1 class="card-title mb-0">{{ question.title }}</h1>
|
||||
|
||||
<!-- محتوای سوال -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-start justify-between mb-6">
|
||||
<h1 class="text-3xl font-bold text-gray-900 leading-tight">{{ question.title }}</h1>
|
||||
{% if question.isSolved %}
|
||||
<span class="badge bg-success fs-6">
|
||||
<i class="fas fa-check me-1"></i>حل شده
|
||||
<span class="inline-flex items-center space-x-1 space-x-reverse px-4 py-2 bg-green-100 text-green-800 text-sm font-medium rounded-full">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
<span>حل شده</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="question-content mb-3">
|
||||
<div class="prose prose-lg max-w-none text-gray-800 leading-relaxed mb-6">
|
||||
{{ question.content|markdown|raw }}
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="tags">
|
||||
<div class="flex flex-wrap items-center justify-between gap-4 pt-6 border-t border-gray-200">
|
||||
<!-- تگها -->
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{% for tagRelation in question.tagRelations %}
|
||||
<a href="{{ path('qa_tag_questions', {'name': tagRelation.tag.name}) }}"
|
||||
class="badge bg-light text-dark text-decoration-none me-1">
|
||||
class="inline-flex items-center px-3 py-1 bg-blue-100 text-blue-800 text-sm font-medium rounded-full hover:bg-blue-200 transition-colors duration-200">
|
||||
{{ tagRelation.tag.name }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="text-muted small">
|
||||
<i class="fas fa-user me-1"></i>{{ question.author.name }}
|
||||
<i class="fas fa-clock ms-3 me-1"></i>{{ question.createdAt|date('Y/m/d H:i') }}
|
||||
<i class="fas fa-eye ms-3 me-1"></i>{{ question.views }} بازدید
|
||||
|
||||
<!-- اطلاعات سوال -->
|
||||
<div class="flex items-center space-x-6 space-x-reverse text-sm text-gray-500">
|
||||
<div class="flex items-center space-x-1 space-x-reverse">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
|
||||
</svg>
|
||||
<span>{{ question.author.name }}</span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-1 space-x-reverse">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<span>{{ question.createdAt|date('Y/m/d H:i') }}</span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-1 space-x-reverse">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
|
||||
</svg>
|
||||
<span>{{ question.views }} بازدید</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -70,85 +93,119 @@
|
|||
</div>
|
||||
|
||||
<!-- پاسخها -->
|
||||
<div class="mb-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h3>
|
||||
<i class="fas fa-comments me-2"></i>پاسخها
|
||||
<span class="badge bg-primary">{{ totalAnswers }}</span>
|
||||
</h3>
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h2 class="text-2xl font-bold text-gray-900 flex items-center">
|
||||
<svg class="w-6 h-6 text-blue-600 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
|
||||
</svg>
|
||||
پاسخها
|
||||
<span class="inline-flex items-center px-3 py-1 bg-blue-100 text-blue-800 text-sm font-medium rounded-full mr-3">
|
||||
{{ totalAnswers }}
|
||||
</span>
|
||||
</h2>
|
||||
{% if app.user and 'ROLE_CUSTOMER' in app.user.roles %}
|
||||
<a href="{{ path('qa_answer', {'id': question.id}) }}" class="btn btn-primary">
|
||||
<i class="fas fa-plus me-2"></i>پاسخ دهید
|
||||
<a href="{{ path('qa_answer', {'id': question.id}) }}"
|
||||
class="inline-flex items-center space-x-2 space-x-reverse px-6 py-3 bg-blue-600 text-white rounded-xl hover:bg-blue-700 transition-all duration-200 font-medium shadow-lg hover:shadow-xl transform hover:-translate-y-0.5">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<line x1="12" y1="5" x2="12" y2="19"></line>
|
||||
<line x1="5" y1="12" x2="19" y2="12"></line>
|
||||
</svg>
|
||||
<span>پاسخ دهید</span>
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{{ path('customer_login') }}" class="btn btn-outline-primary">
|
||||
<i class="fas fa-sign-in-alt me-2"></i>ورود برای پاسخ دادن
|
||||
<a href="{{ path('customer_login') }}"
|
||||
class="inline-flex items-center space-x-2 space-x-reverse px-6 py-3 bg-gray-100 text-gray-700 rounded-xl hover:bg-gray-200 transition-all duration-200 font-medium">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path>
|
||||
<polyline points="10,17 15,12 10,7"></polyline>
|
||||
<line x1="15" y1="12" x2="3" y2="12"></line>
|
||||
</svg>
|
||||
<span>ورود برای پاسخ دادن</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if answers is empty %}
|
||||
<div class="card">
|
||||
<div class="card-body text-center py-5">
|
||||
<i class="fas fa-comment-slash fa-3x text-muted mb-3"></i>
|
||||
<h4 class="text-muted">هنوز پاسخی داده نشده</h4>
|
||||
<p class="text-muted">اولین کسی باشید که به این سوال پاسخ میدهد.</p>
|
||||
<div class="bg-white rounded-2xl shadow-soft p-12 text-center">
|
||||
<div class="max-w-md mx-auto">
|
||||
<svg class="w-16 h-16 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
|
||||
</svg>
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">هنوز پاسخی داده نشده</h3>
|
||||
<p class="text-gray-600">اولین کسی باشید که به این سوال پاسخ میدهد.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="space-y-6">
|
||||
{% for answer in answers %}
|
||||
<div class="card mb-3 answer-card {{ answer.isAccepted ? 'border-success' : '' }}">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-1 text-center">
|
||||
<div class="vote-section">
|
||||
<button class="btn btn-outline-success btn-sm vote-btn"
|
||||
<div class="bg-white rounded-2xl shadow-soft overflow-hidden {{ answer.isAccepted ? 'ring-2 ring-green-200 border-green-200' : '' }}">
|
||||
<div class="p-8">
|
||||
<div class="flex space-x-6 space-x-reverse">
|
||||
<!-- سیستم رایدهی پاسخ -->
|
||||
<div class="flex flex-col items-center space-y-2 min-w-0">
|
||||
<button class="vote-btn w-10 h-10 flex items-center justify-center rounded-lg border-2 border-green-200 text-green-600 hover:bg-green-50 hover:border-green-300 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
data-type="answer"
|
||||
data-id="{{ answer.id }}"
|
||||
data-upvote="true"
|
||||
{% if not app.user or 'ROLE_CUSTOMER' not in app.user.roles %}disabled{% endif %}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="18,15 12,9 6,15"></polyline>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="vote-count mt-2 mb-2" id="answer-votes-{{ answer.id }}">
|
||||
<div class="text-2xl font-bold text-gray-900" id="answer-votes-{{ answer.id }}">
|
||||
{{ answer.votes }}
|
||||
</div>
|
||||
<button class="btn btn-outline-danger btn-sm vote-btn"
|
||||
<button class="vote-btn w-10 h-10 flex items-center justify-center rounded-lg border-2 border-red-200 text-red-600 hover:bg-red-50 hover:border-red-300 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
data-type="answer"
|
||||
data-id="{{ answer.id }}"
|
||||
data-upvote="false"
|
||||
{% if not app.user or 'ROLE_CUSTOMER' not in app.user.roles %}disabled{% endif %}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="6,9 12,15 18,9"></polyline>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-11">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
<div class="answer-content">
|
||||
|
||||
<!-- محتوای پاسخ -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-start justify-between mb-4">
|
||||
<div class="prose prose-lg max-w-none text-gray-800 leading-relaxed">
|
||||
{{ answer.content|markdown|raw }}
|
||||
</div>
|
||||
{% if answer.isAccepted %}
|
||||
<span class="badge bg-success ms-2">
|
||||
<i class="fas fa-check me-1"></i>پاسخ پذیرفته شده
|
||||
<span class="inline-flex items-center space-x-1 space-x-reverse px-3 py-1 bg-green-100 text-green-800 text-sm font-medium rounded-full mr-4">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
<span>پاسخ پذیرفته شده</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="text-muted small">
|
||||
<i class="fas fa-user me-1"></i>{{ answer.author.name }}
|
||||
<i class="fas fa-clock ms-3 me-1"></i>{{ answer.createdAt|date('Y/m/d H:i') }}
|
||||
<div class="flex items-center justify-between pt-4 border-t border-gray-200">
|
||||
<div class="flex items-center space-x-4 space-x-reverse text-sm text-gray-500">
|
||||
<div class="flex items-center space-x-1 space-x-reverse">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
|
||||
</svg>
|
||||
<span>{{ answer.author.name }}</span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-1 space-x-reverse">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<span>{{ answer.createdAt|date('Y/m/d H:i') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if app.user and app.user == question.author and not answer.isAccepted %}
|
||||
<button class="btn btn-outline-success btn-sm accept-answer-btn"
|
||||
<button class="accept-answer-btn inline-flex items-center space-x-2 space-x-reverse px-4 py-2 bg-green-100 text-green-700 rounded-lg hover:bg-green-200 transition-colors duration-200 font-medium"
|
||||
data-answer-id="{{ answer.id }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-1">
|
||||
<polyline points="20,6 9,17 4,12"></polyline>
|
||||
</svg>پذیرفتن پاسخ
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
<span>پذیرفتن پاسخ</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
@ -157,95 +214,80 @@
|
|||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- صفحهبندی پاسخها -->
|
||||
{% if totalPages > 1 %}
|
||||
<nav aria-label="صفحهبندی پاسخها" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
<div class="mt-8">
|
||||
<nav class="flex justify-center" aria-label="صفحهبندی پاسخها">
|
||||
<div class="flex items-center space-x-2 space-x-reverse">
|
||||
<!-- دکمه صفحه قبل -->
|
||||
{% if currentPage > 1 %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ currentPage - 1 }}">قبلی</a>
|
||||
</li>
|
||||
<a href="?page={{ currentPage - 1 }}"
|
||||
class="flex items-center space-x-2 space-x-reverse px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 hover:text-gray-700 transition-all duration-200">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
<span>قبلی</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<!-- شماره صفحات -->
|
||||
<div class="flex items-center space-x-1 space-x-reverse">
|
||||
{% for page in 1..totalPages %}
|
||||
{% if page == currentPage %}
|
||||
<li class="page-item active">
|
||||
<span class="page-link">{{ page }}</span>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page }}">{{ page }}</a>
|
||||
</li>
|
||||
<span class="px-4 py-2 text-sm font-medium text-white bg-blue-600 border border-blue-600 rounded-lg">
|
||||
{{ page }}
|
||||
</span>
|
||||
{% elseif page <= currentPage + 2 and page >= currentPage - 2 %}
|
||||
<a href="?page={{ page }}"
|
||||
class="px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 hover:text-gray-700 transition-all duration-200">
|
||||
{{ page }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- دکمه صفحه بعد -->
|
||||
{% if currentPage < totalPages %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ currentPage + 1 }}">بعدی</a>
|
||||
</li>
|
||||
<a href="?page={{ currentPage + 1 }}"
|
||||
class="flex items-center space-x-2 space-x-reverse px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 hover:text-gray-700 transition-all duration-200">
|
||||
<span>بعدی</span>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
|
||||
</svg>
|
||||
</a>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- دکمه بازگشت -->
|
||||
<div class="text-center">
|
||||
<a href="{{ path('qa_index') }}" class="btn btn-outline-secondary">
|
||||
<i class="fas fa-arrow-right me-2"></i>بازگشت به لیست سوالات
|
||||
<div class="text-center mt-8">
|
||||
<a href="{{ path('qa_index') }}"
|
||||
class="inline-flex items-center space-x-2 space-x-reverse px-6 py-3 bg-gray-100 text-gray-700 rounded-xl hover:bg-gray-200 transition-all duration-200 font-medium">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
|
||||
</svg>
|
||||
<span>بازگشت به لیست سوالات</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.vote-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.vote-btn {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.vote-count {
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
min-width: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.answer-card.border-success {
|
||||
border-left: 4px solid #198754 !important;
|
||||
}
|
||||
|
||||
.question-content, .answer-content {
|
||||
line-height: 1.6;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.tags .badge {
|
||||
font-size: 0.9rem;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.tags .badge:hover {
|
||||
background-color: #0d6efd !important;
|
||||
color: white !important;
|
||||
}
|
||||
</style>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
function initializeVoteButtons() {
|
||||
// Wait for notification system to be available
|
||||
if (typeof window.notification === 'undefined') {
|
||||
console.log('Waiting for notification system...');
|
||||
setTimeout(initializeVoteButtons, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
// رایدهی
|
||||
document.querySelectorAll('.vote-btn').forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
|
|
@ -266,7 +308,9 @@ function initializeVoteButtons() {
|
|||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
alert(data.error);
|
||||
if (window.notification) {
|
||||
window.notification.error(data.error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -275,27 +319,35 @@ function initializeVoteButtons() {
|
|||
// تغییر رنگ دکمهها
|
||||
const buttons = document.querySelectorAll(`[data-type="${type}"][data-id="${id}"]`);
|
||||
buttons.forEach(btn => {
|
||||
btn.classList.remove('btn-success', 'btn-danger', 'btn-outline-success', 'btn-outline-danger');
|
||||
btn.classList.add(btn.dataset.upvote === 'true' ? 'btn-outline-success' : 'btn-outline-danger');
|
||||
btn.classList.remove('bg-green-500', 'bg-red-500', 'border-green-500', 'border-red-500', 'text-white');
|
||||
btn.classList.add(btn.dataset.upvote === 'true' ? 'border-green-200 text-green-600' : 'border-red-200 text-red-600');
|
||||
});
|
||||
|
||||
if (data.userVote) {
|
||||
const activeButton = document.querySelector(`[data-type="${type}"][data-id="${id}"][data-upvote="${data.userVote === 'up' ? 'true' : 'false'}"]`);
|
||||
if (activeButton) {
|
||||
activeButton.classList.remove('btn-outline-success', 'btn-outline-danger');
|
||||
activeButton.classList.add(data.userVote === 'up' ? 'btn-success' : 'btn-danger');
|
||||
activeButton.classList.remove('border-green-200', 'border-red-200', 'text-green-600', 'text-red-600');
|
||||
activeButton.classList.add(data.userVote === 'up' ? 'bg-green-500 text-white border-green-500' : 'bg-red-500 text-white border-red-500');
|
||||
}
|
||||
if (window.notification) {
|
||||
window.notification.success('رای شما ثبت شد');
|
||||
}
|
||||
} else {
|
||||
// اگر رای حذف شده، همه دکمهها را به حالت عادی برگردان
|
||||
buttons.forEach(btn => {
|
||||
btn.classList.remove('btn-success', 'btn-danger');
|
||||
btn.classList.add(btn.dataset.upvote === 'true' ? 'btn-outline-success' : 'btn-outline-danger');
|
||||
btn.classList.remove('bg-green-500', 'bg-red-500', 'text-white', 'border-green-500', 'border-red-500');
|
||||
btn.classList.add(btn.dataset.upvote === 'true' ? 'border-green-200 text-green-600' : 'border-red-200 text-red-600');
|
||||
});
|
||||
if (window.notification) {
|
||||
window.notification.info('رای شما حذف شد');
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('خطا در ارسال رای');
|
||||
if (window.notification) {
|
||||
window.notification.error('خطا در ارسال رای. لطفاً دوباره تلاش کنید.');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -305,10 +357,17 @@ function initializeVoteButtons() {
|
|||
button.addEventListener('click', function() {
|
||||
const answerId = this.dataset.answerId;
|
||||
|
||||
if (!confirm('آیا مطمئن هستید که میخواهید این پاسخ را بپذیرید؟')) {
|
||||
// Show confirmation dialog
|
||||
const confirmed = confirm('آیا مطمئن هستید که میخواهید این پاسخ را بپذیرید؟');
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Show loading state
|
||||
const originalText = this.innerHTML;
|
||||
this.innerHTML = '<div class="loading-spinner"></div>';
|
||||
this.disabled = true;
|
||||
|
||||
fetch(`/qa/answer/${answerId}/accept`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
|
@ -320,22 +379,56 @@ function initializeVoteButtons() {
|
|||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
alert(data.error);
|
||||
if (window.notification) {
|
||||
window.notification.error(data.error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.notification) {
|
||||
window.notification.success('پاسخ با موفقیت پذیرفته شد');
|
||||
}
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 1500);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('خطا در پذیرفتن پاسخ');
|
||||
if (window.notification) {
|
||||
window.notification.error('خطا در پذیرفتن پاسخ. لطفاً دوباره تلاش کنید.');
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
// Reset button state
|
||||
this.innerHTML = originalText;
|
||||
this.disabled = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// اجرا در هر دو حالت
|
||||
document.addEventListener('DOMContentLoaded', initializeVoteButtons);
|
||||
document.addEventListener('turbo:load', initializeVoteButtons);
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Wait for notification system to be available
|
||||
const checkNotification = () => {
|
||||
if (window.notification) {
|
||||
initializeVoteButtons();
|
||||
} else {
|
||||
setTimeout(checkNotification, 100);
|
||||
}
|
||||
};
|
||||
checkNotification();
|
||||
});
|
||||
document.addEventListener('turbo:load', function() {
|
||||
// Wait for notification system to be available
|
||||
const checkNotification = () => {
|
||||
if (window.notification) {
|
||||
initializeVoteButtons();
|
||||
} else {
|
||||
setTimeout(checkNotification, 100);
|
||||
}
|
||||
};
|
||||
checkNotification();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,335 +0,0 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
{% block title %}
|
||||
دیدگاههای کاربران
|
||||
{% endblock %}
|
||||
|
||||
{% block des %}
|
||||
دیدگاه سایر کاربران استفاده کننده از حسابیکس دید بهترین برای انتخاب محصولی عالی را برای شما مهیا می کند.
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container mt-3">
|
||||
<div class="mb-3">
|
||||
<h3 class="mb-4">نظرات کاربران درباره حسابیکس</h3>
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto text-center">
|
||||
<h3 class="display-2 fw-bold">4.5</h3>
|
||||
<span class="fs-6">
|
||||
<i class="bi bi-star-fill text-warning"></i>
|
||||
<i class="bi bi-star-fill text-warning"></i>
|
||||
<i class="bi bi-star-fill text-warning"></i>
|
||||
<i class="bi bi-star-fill text-warning"></i>
|
||||
<i class="bi bi-star-half text-warning"></i>
|
||||
</span>
|
||||
<p class="mb-0 fs-6">(بر اساس 27 نظر)</p>
|
||||
</div>
|
||||
<!-- Progress Bar -->
|
||||
<div class="col order-3 order-md-2">
|
||||
<div class="progress mb-3" style="height: 6px;">
|
||||
<div class="progress-bar bg-warning" role="progressbar" style="width: 90%;" aria-valuenow="90" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<div class="progress mb-3" style="height: 6px;">
|
||||
<div class="progress-bar bg-warning" role="progressbar" style="width: 80%;" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<div class="progress mb-3" style="height: 6px;">
|
||||
<div class="progress-bar bg-warning" role="progressbar" style="width: 70%;" aria-valuenow="70" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<div class="progress mb-3" style="height: 6px;">
|
||||
<div class="progress-bar bg-warning" role="progressbar" style="width: 60%;" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<div class="progress mb-0" style="height: 6px;">
|
||||
<div class="progress-bar bg-warning" role="progressbar" style="width: 50%;" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="col-md-auto col-6 order-2 order-md-3">
|
||||
<!-- Rating -->
|
||||
<div>
|
||||
<span class="fs-6">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="ms-1">53%</span>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<span class="fs-6">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-light" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="ms-1">36%</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="fs-6">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-light" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-light" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="ms-1">9%</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="fs-6">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-light" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-light" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-light" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="ms-1">3%</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="fs-6">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-light" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-light" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-light" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-light" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="ms-1">2%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="my-5">
|
||||
<div class="mb-3">
|
||||
<div
|
||||
class="d-lg-flex align-items-center justify-content-between mb-5">
|
||||
<!-- Reviews -->
|
||||
<div class="mb-3 mb-lg-0">
|
||||
<h3 class="mb-0">نظرات کاربران</h3>
|
||||
</div>
|
||||
<div>
|
||||
<form class="form-inline">
|
||||
<div class="d-flex align-items-center me-2">
|
||||
<span class="position-absolute ps-3">
|
||||
<i class="fe fe-search"></i>
|
||||
</span>
|
||||
<input type="search" class="form-control ps-6" placeholder="جستجوی نظرات">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Rating -->
|
||||
<div class="d-flex align-items-start border-bottom pb-4 mb-4">
|
||||
<img src="{{asset('assets/images/avatar/avatar-2.jpg')}}" alt="" class="rounded-circle avatar-lg">
|
||||
<div class="ms-3">
|
||||
<h4 class="mb-1">
|
||||
حمیدرضا تینای تهرانی
|
||||
<span class="ms-1 fs-6">2 روز پیش</span>
|
||||
</h4>
|
||||
<div class="mb-2">
|
||||
<span class="fs-6">
|
||||
<i class="bi bi-star-fill text-warning"></i>
|
||||
<i class="bi bi-star-fill text-warning"></i>
|
||||
<i class="bi bi-star-fill text-warning"></i>
|
||||
<i class="bi bi-star-fill text-warning"></i>
|
||||
<i class="bi bi-star-fill text-warning"></i>
|
||||
</span>
|
||||
</div>
|
||||
<p>حسابیکس بهترین نرم افزار حسابداری آنلاینی هست که تا حالا استفاده کردم. امکاناتش کامل و پشتیبانی عالی و بهروزرسانیهای مداوم باعث شده که همیشه از جدیدترین امکانات بهرهمند بشم.</p>
|
||||
<div class="d-lg-flex">
|
||||
<p class="mb-0">آیا این نظر برای شما مفید بود؟</p>
|
||||
<a href="#" class="btn btn-xs btn-primary ms-lg-3">بله</a>
|
||||
<a href="#" class="btn btn-xs btn-outline-secondary ms-1">خیر</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Rating -->
|
||||
<div class="d-flex align-items-start border-bottom pb-4 mb-4">
|
||||
<img src="../assets/images/avatar/avatar-3.jpg" alt="" class="rounded-circle avatar-lg">
|
||||
<div class="ms-3">
|
||||
<h4 class="mb-1">Arthur Williamson
|
||||
<span class="ms-1 fs-6 ">3 Days
|
||||
ago</span>
|
||||
</h4>
|
||||
<div class="mb-2">
|
||||
<span class="fs-6">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<p>Its pretty good.Just a reminder that there are also
|
||||
students with Windows, meaning Figma its a bit different
|
||||
of yours. Thank you!</p>
|
||||
<div class="d-lg-flex">
|
||||
<p class="mb-0">Was this review helpful?</p>
|
||||
<a href="#" class="btn btn-xs btn-primary ms-lg-3">Yes</a>
|
||||
<a href="#" class="btn btn-xs btn-outline-secondary ms-1">No</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Rating -->
|
||||
<div class="d-flex align-items-start border-bottom pb-4 mb-4">
|
||||
<img src="../assets/images/avatar/avatar-4.jpg" alt="" class="rounded-circle avatar-lg">
|
||||
<div class="ms-3">
|
||||
<h4 class="mb-1">Claire Jones
|
||||
<span class="ms-1 fs-6 ">4 Days
|
||||
ago</span>
|
||||
</h4>
|
||||
<div class="mb-2">
|
||||
<span class="fs-6">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<p>
|
||||
Great course for learning Figma, the only bad detail
|
||||
would be that some icons are not included in the assets.
|
||||
But 90% of the icons needed are included, and the voice
|
||||
of the instructor was very clear and easy to understood.
|
||||
</p>
|
||||
<div class="d-lg-flex">
|
||||
<p class="mb-0">Was this review helpful?</p>
|
||||
<a href="#" class="btn btn-xs btn-primary ms-lg-3">Yes</a>
|
||||
<a href="#" class="btn btn-xs btn-outline-secondary ms-1">No</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Rating -->
|
||||
<div class="d-flex align-items-start">
|
||||
<img src="../assets/images/avatar/avatar-5.jpg" alt="" class="rounded-circle avatar-lg">
|
||||
<div class="ms-3">
|
||||
<h4 class="mb-1">
|
||||
Bessie Pena
|
||||
<span class="ms-1 fs-6 ">5 Days
|
||||
ago</span>
|
||||
</h4>
|
||||
<div class="mb-2">
|
||||
<span class="fs-6">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-star-fill text-warning" viewbox="0 0 16 16">
|
||||
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<p>
|
||||
I have really enjoyed this class and learned a lot,
|
||||
found it very inspiring and helpful, thank you!
|
||||
|
||||
</p>
|
||||
<div class="d-lg-flex">
|
||||
<p class="mb-0">Was this review helpful?</p>
|
||||
<a href="#" class="btn btn-xs btn-primary ms-lg-3">Yes</a>
|
||||
<a href="#" class="btn btn-xs btn-outline-secondary ms-1">No</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.avatar-lg {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
object-fit: cover;
|
||||
}
|
||||
.progress {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
.progress-bar {
|
||||
background-color: #ffc107;
|
||||
}
|
||||
.btn-xs {
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
.border-bottom {
|
||||
border-bottom: 1px solid #dee2e6 !important;
|
||||
}
|
||||
.text-warning {
|
||||
color: #ffc107 !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
|
@ -59,6 +59,9 @@ Encore
|
|||
// enables Sass/SCSS support
|
||||
.enableSassLoader()
|
||||
|
||||
// enables PostCSS support for Tailwind
|
||||
.enablePostCssLoader()
|
||||
|
||||
// uncomment if you use TypeScript
|
||||
//.enableTypeScriptLoader()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue