progress in site admin dashboard

This commit is contained in:
Hesabix 2025-04-06 14:20:29 +00:00
parent 335166d839
commit 0111427a09
8 changed files with 115 additions and 126 deletions

24
package-lock.json generated
View file

@ -2123,8 +2123,14 @@
}
},
"node_modules/@symfony/ux-turbo": {
"resolved": "vendor/symfony/ux-turbo/assets",
"link": true
"version": "0.1.0",
"resolved": "file:vendor/symfony/ux-turbo/assets",
"dev": true,
"license": "MIT",
"peerDependencies": {
"@hotwired/stimulus": "^3.0.0",
"@hotwired/turbo": "^7.1.1 || ^8.0"
}
},
"node_modules/@symfony/webpack-encore": {
"version": "5.0.1",
@ -6875,20 +6881,6 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"vendor/symfony/ux-turbo/assets": {
"name": "@symfony/ux-turbo",
"version": "0.1.0",
"dev": true,
"license": "MIT",
"devDependencies": {
"@hotwired/stimulus": "^3.0.0",
"@hotwired/turbo": "^7.1.0 || ^8.0"
},
"peerDependencies": {
"@hotwired/stimulus": "^3.0.0",
"@hotwired/turbo": "^7.1.1 || ^8.0"
}
}
}
}

38
public/css/login.css Normal file
View file

@ -0,0 +1,38 @@
/* public/css/login.css */
body {
direction: rtl;
text-align: right;
font-family: 'Vazir', 'Tahoma', sans-serif; /* فونت فارسی دلخواه */
}
.login-wrapper {
direction: rtl;
}
.form-group label {
text-align: right;
}
.form-control {
direction: rtl;
text-align: right;
}
.btn {
direction: rtl;
}
.checkbox label {
padding-right: 25px; /* فاصله برای چک‌باکس */
padding-left: 0;
}
.login-box {
margin-right: auto;
margin-left: auto;
}
/* تنظیمات اضافی برای المان‌های خاص */
.login-box-header h1 {
text-align: right;
}

View file

@ -39,39 +39,16 @@ class DashboardController extends AbstractDashboardController
public function configureDashboard(): Dashboard
{
return Dashboard::new()
// you can include HTML contents too (e.g. to link to an image)
->setTitle('پیشخوان')
// by default EasyAdmin displays a black square as its default favicon;
// use this method to display a custom favicon: the given path is passed
// "as is" to the Twig asset() function:
// <link rel="shortcut icon" href="{{ asset('...') }}">
->setFaviconPath('favicon/favicon.ico')
// the domain used by default is 'messages'
->setTranslationDomain('admin')
// set this option if you prefer the page content to span the entire
// browser width, instead of the default design which sets a max width
->renderContentMaximized()
// by default, the UI color scheme is 'auto', which means that the backend
// will use the same mode (light/dark) as the operating system and will
// change in sync when the OS mode changes.
// Use this option to set which mode ('light', 'dark' or 'auto') will users see
// by default in the backend (users can change it via the color scheme selector)
->setDefaultColorScheme('dark')
// instead of magic strings, you can use constants as the value of
// this option: EasyCorp\Bundle\EasyAdminBundle\Config\Option\ColorScheme::DARK
// by default, all backend URLs are generated as absolute URLs. If you
// need to generate relative URLs instead, call this method
->generateRelativeUrls()
->setLocales(['en','fa'])
// to further customize the locale option, pass an instance of
// EasyCorp\Bundle\EasyAdminBundle\Config\Locale
;
->setLocales([
'fa' => Locale::new('fa', 'فارسی', 'fa_IR'), // زبان پیش‌فرض
'en' => Locale::new('en', 'English', 'en_US'),
]);
}
public function configureMenuItems(): iterable

View file

@ -5,15 +5,14 @@ namespace App\Controller\Admin;
use App\Entity\Cat;
use App\Entity\Post;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Config\Filters;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField;
use EasyCorp\Bundle\EasyAdminBundle\Field\CodeEditorField;
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ImageField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Filter\EntityFilter;
class PostCrudController extends AbstractCrudController
{
@ -32,21 +31,25 @@ class PostCrudController extends AbstractCrudController
TextField::new('title', 'عنوان'),
TextareaField::new('intro', 'خلاصه مطلب')->hideOnIndex(),
TextEditorField::new('body', 'متن')->hideOnIndex(),
CodeEditorField::new('plain', 'ساختار')->hideOnIndex(),
TextField::new('keywords', 'کلیدواژه‌ها'),
ImageField::new('mainPic','تصویر شاخص')
->setUploadDir('/public/uploaded/')
->setBasePath('/uploaded/')
ImageField::new('mainPic', 'تصویر شاخص')
->setUploadDir('/public/uploaded/')
->setBasePath('/uploaded/'),
];
}
public function configureCrud(Crud $crud): Crud
{
return $crud
// the labels used to refer to this entity in titles, buttons, etc.
->setEntityLabelInSingular('محتوا')
->setEntityLabelInPlural('محتواها')
;
->setDefaultSort(['dateSubmit' => 'DESC']); // مرتب‌سازی پیش‌فرض بر اساس تاریخ ارسال (جدیدترین)
}
public function configureFilters(Filters $filters): Filters
{
return $filters
->add(EntityFilter::new('cat', 'نوع محتوا')); // فیلتر برای نوع محتوا
}
public function createEntity(string $entityFqcn)
@ -57,5 +60,4 @@ class PostCrudController extends AbstractCrudController
$item->setViews(0);
return $item;
}
}
}

View file

@ -9,6 +9,8 @@ use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\HttpFoundation\Request;
class PageController extends AbstractController
{
@ -23,26 +25,48 @@ class PageController extends AbstractController
]);
}
#[Route('/blog/{page}', name: 'app_blog_home')]
public function app_blog_home(EntityManagerInterface $entityManagerInterface, $page = 1): Response
#[Route('/blog/{page}', name: 'app_blog_home', defaults: ['page' => 1])]
public function app_blog_home(EntityManagerInterface $entityManagerInterface, Request $request, $page = 1): Response
{
$perpage = 9;
$posts = $entityManagerInterface->getRepository(Post::class)->findByCat('blog',$perpage,$page);
$cat = $entityManagerInterface->getRepository(Cat::class)->findOneBy(['code'=>'blog']);
$count = $entityManagerInterface->getRepository(Post::class)->count(['cat'=>$cat]);
if(fmod($count,$perpage) == 0){
$maxpages = $count/$perpage;
$search = $request->query->get('search', ''); // پارامتر جستجو از URL
$postRepository = $entityManagerInterface->getRepository(Post::class);
$catRepository = $entityManagerInterface->getRepository(Cat::class);
// پیدا کردن دسته‌بندی "blog"
$cat = $catRepository->findOneBy(['code' => 'blog']);
// گرفتن پست‌ها با فیلتر جستجو
$queryBuilder = $postRepository->createQueryBuilder('p')
->where('p.cat = :cat')
->setParameter('cat', $cat)
->orderBy('p.dateSubmit', 'DESC'); // مرتب‌سازی بر اساس جدیدترین
if ($search) {
$queryBuilder->andWhere('p.title LIKE :search OR p.intro LIKE :search')
->setParameter('search', "%$search%");
}
else{
$maxpages = ($count/$perpage) + 1;
}
$maxpages = $count / $perpage;
$count = count($queryBuilder->getQuery()->getResult());
$maxpages = ceil($count / $perpage); // محاسبه حداکثر صفحات
$posts = $queryBuilder->setMaxResults($perpage)
->setFirstResult(($page - 1) * $perpage)
->getQuery()
->getResult();
// گرفتن همه دسته‌بندی‌ها برای سایدبار
$categories = $catRepository->findAll();
return $this->render('post/blog_home.html.twig', [
'posts' => $posts,
'page' => $page,
'perpage'=> $perpage,
'perpage' => $perpage,
'count' => $count,
'maxpages' => $maxpages
'maxpages' => $maxpages,
'categories' => $categories,
'search' => $search,
]);
}

View file

@ -14,55 +14,19 @@ class SecurityController extends AbstractController
$error = $authenticationUtils->getLastAuthenticationError();
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('@EasyAdmin/page/login.html.twig', [
// parameters usually defined in Symfony login forms
return $this->render('/admin/login.html.twig', [
'error' => $error,
'last_username' => $lastUsername,
// OPTIONAL parameters to customize the login form:
// the translation_domain to use (define this option only if you are
// rendering the login template in a regular Symfony controller; when
// rendering it from an EasyAdmin Dashboard this is automatically set to
// the same domain as the rest of the Dashboard)
'translation_domain' => 'admin',
// by default EasyAdmin displays a black square as its default favicon;
// use this method to display a custom favicon: the given path is passed
// "as is" to the Twig asset() function:
//
// the title visible above the login form (define this option only if you are
// rendering the login template in a regular Symfony controller; when rendering
// it from an EasyAdmin Dashboard this is automatically set as the Dashboard title)
'page_title' => 'ورود',
// the string used to generate the CSRF token. If you don't define
// this parameter, the login form won't include a CSRF token
'csrf_token_intention' => 'authenticate',
// the URL users are redirected to after the login (default: '/admin')
'target_path' => $this->generateUrl('admin'),
// the label displayed for the username form field (the |trans filter is applied to it)
'target_path' => $this->generateUrl('admin', ['_locale' => 'fa']),
'username_label' => 'پست الکترونیکی',
// the label displayed for the password form field (the |trans filter is applied to it)
'password_label' => 'کلمه عبور',
// the label displayed for the Sign In form button (the |trans filter is applied to it)
'sign_in_label' => 'ورود',
// whether to enable or not the "forgot password?" link (default: false)
'forgot_password_enabled' => false,
// whether to enable or not the "remember me" checkbox (default: false)
'remember_me_enabled' => true,
// whether to check by default the "remember me" checkbox (default: false)
'remember_me_checked' => true,
// the label displayed for the remember me checkbox (the |trans filter is applied to it)
'remember_me_label' => 'مرا به یاد داشته باش',
]);
}

View file

@ -8,9 +8,12 @@ use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\UX\Turbo\Attribute\Broadcast;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
#[ORM\Entity(repositoryClass: PostRepository::class)]
#[Broadcast]
#[UniqueEntity(fields: ['url'], message: 'این URL قبلاً استفاده شده است.')]
class Post
{
#[ORM\Id]
@ -34,7 +37,8 @@ class Post
#[ORM\Column(nullable: true)]
private ?bool $publish = null;
#[ORM\Column(length: 255, nullable: true)]
#[ORM\Column(length: 255, nullable: true, unique: true)]
#[Assert\NotBlank(message: 'URL نمی‌تواند خالی باشد', allowNull: false)]
private ?string $url = null;
#[ORM\Column(length: 255, nullable: true)]
@ -93,7 +97,6 @@ class Post
public function setTitle(?string $title): static
{
$this->title = $title;
return $this;
}
@ -105,7 +108,6 @@ class Post
public function setSubmitter(?User $submitter): static
{
$this->submitter = $submitter;
return $this;
}
@ -117,7 +119,6 @@ class Post
public function setBody(?string $body): static
{
$this->body = $body;
return $this;
}
@ -129,7 +130,6 @@ class Post
public function setDateSubmit(string $dateSubmit): static
{
$this->dateSubmit = $dateSubmit;
return $this;
}
@ -141,7 +141,6 @@ class Post
public function setPublish(?bool $publish): static
{
$this->publish = $publish;
return $this;
}
@ -153,7 +152,6 @@ class Post
public function setUrl(?string $url): static
{
$this->url = $url;
return $this;
}
@ -165,7 +163,6 @@ class Post
public function setMainPic(?string $mainPic): static
{
$this->mainPic = $mainPic;
return $this;
}
@ -177,7 +174,6 @@ class Post
public function setPlain(?string $plain): static
{
$this->plain = $plain;
return $this;
}
@ -189,7 +185,6 @@ class Post
public function setVersion(?string $version): static
{
$this->version = $version;
return $this;
}
@ -201,7 +196,6 @@ class Post
public function setKeywords(?string $keywords): static
{
$this->keywords = $keywords;
return $this;
}
@ -213,7 +207,6 @@ class Post
public function setSort(?string $sort): static
{
$this->sort = $sort;
return $this;
}
@ -225,7 +218,6 @@ class Post
public function setCat(?Cat $cat): static
{
$this->cat = $cat;
return $this;
}
@ -242,14 +234,12 @@ class Post
if (!$this->tree->contains($tree)) {
$this->tree->add($tree);
}
return $this;
}
public function removeTree(Tree $tree): static
{
$this->tree->removeElement($tree);
return $this;
}
@ -267,19 +257,16 @@ class Post
$this->comments->add($comment);
$comment->setPost($this);
}
return $this;
}
public function removeComment(Comment $comment): static
{
if ($this->comments->removeElement($comment)) {
// set the owning side to null (unless already changed)
if ($comment->getPost() === $this) {
$comment->setPost(null);
}
}
return $this;
}
@ -291,7 +278,6 @@ class Post
public function setIntro(?string $intro): static
{
$this->intro = $intro;
return $this;
}
@ -303,7 +289,6 @@ class Post
public function setViews(?string $views): static
{
$this->views = $views;
return $this;
}
}
}

View file

@ -0,0 +1,7 @@
{# templates/easy_admin/page/login.html.twig #}
{% extends '@!EasyAdmin/page/login.html.twig' %}
{% block head %}
{{ parent() }}
<link rel="stylesheet" href="/css/login.css">
{% endblock %}