feat: Add City entity methods and migration for title field

- Created a new JSON file for the City entity's AST representation, detailing its methods and properties.
- Added a migration to alter the cities table by adding a nullable title column.
This commit is contained in:
hamed
2026-07-08 12:19:06 +03:30
parent 94541ad609
commit ccbb1d0b1f
25 changed files with 1328 additions and 925 deletions
+83 -54
View File
@@ -18,12 +18,12 @@
## فایل‌های مرتبط
| فایل | نقش |
|------|-----|
| `clinicpro/templates/public/home.html.twig` | کل HTML صفحه + JS inline منو/اسکرول (تک‌فایل، extends نمی‌کند) |
| `clinicpro/assets/home/styles.css` | تمام استایل صفحه، شامل `@media (max-width:1000px)` و `@media (max-width:640px)` |
| `clinicpro/src/Shared/Controller/HomeController.php` | فقط `return $this->render('public/home.html.twig')`**نیازی به تغییر ندارد** |
| `clinicpro/assets/home/index.js` | فقط `import './styles.css'` — تغییر نمی‌کند |
| فایل | نقش |
| ---------------------------------------------------- | ------------------------------------------------------------------------------- |
| `clinicpro/templates/public/home.html.twig` | کل HTML صفحه + JS inline منو/اسکرول (تک‌فایل، extends نمی‌کند) |
| `clinicpro/assets/home/styles.css` | تمام استایل صفحه، شامل `@media (max-width:1000px)` و `@media (max-width:640px)` |
| `clinicpro/src/Shared/Controller/HomeController.php` | فقط `return $this->render('public/home.html.twig')`**نیازی به تغییر ندارد** |
| `clinicpro/assets/home/index.js` | فقط `import './styles.css'` — تغییر نمی‌کند |
> توجه: این صفحه ربطی به پنل ادمین React یا API ندارد. فقط Twig + CSS. نیازی به migration، docs/api، یا BaseController نیست.
@@ -37,8 +37,11 @@
```html
<!-- Hero — خط ۴۸ تا ۵۲ -->
<h1 class="reveal">نوبت، پرونده و حساب مطب،<br/>همه یک‌جا</h1>
<p class="reveal d1">کلینیک پرو کارهای روزمره‌ی مطب را سر و سامان می‌دهد؛ از نوبت‌دهی و پرونده‌ی بیمار تا فاکتور و گزارش مالی. دیگر خبری از دفتر نوبت و کاغذبازی نیست.</p>
<h1 class="reveal">نوبت، پرونده و حساب مطب،<br />همه یک‌جا</h1>
<p class="reveal d1">
کلینیک پرو کارهای روزمره‌ی مطب را سر و سامان می‌دهد؛ از نوبت‌دهی و پرونده‌ی
بیمار تا فاکتور و گزارش مالی. دیگر خبری از دفتر نوبت و کاغذبازی نیست.
</p>
<button class="btn btn-coral" id="openRegModal2">ثبت نام دکتر / کلینیک</button>
<a href="#contact" class="btn btn-blue">تماس با ما</a>
```
@@ -46,18 +49,27 @@
```html
<!-- Feature columns — خط ۱۴۲ تا ۱۶۹ (۴ ستون) -->
<h3>پرونده‌ی بیمار</h3>
<p>سابقه، نسخه و آزمایش هر بیمار جای خودش است و هر وقت لازم شد، چند ثانیه‌ای پیدایش می‌کنید.</p>
<p>
سابقه، نسخه و آزمایش هر بیمار جای خودش است و هر وقت لازم شد، چند ثانیه‌ای
پیدایش می‌کنید.
</p>
<!-- ... نوبت‌دهی آنلاین / حساب و کتاب / +۵۰۰ مطب -->
```
```html
<!-- Why icon row — خط ۱۸۱ تا ۲۰۳ -->
<h3>راه‌اندازی با شما</h3> ... <h3>پشتیبانی همیشگی</h3> ... <h3>متناسب با مطب ایرانی</h3> ... <h3>گزارش‌گیری دقیق</h3>
<h3>راه‌اندازی با شما</h3>
...
<h3>پشتیبانی همیشگی</h3>
...
<h3>متناسب با مطب ایرانی</h3>
...
<h3>گزارش‌گیری دقیق</h3>
```
```html
<!-- Devices — خط ۲۱۲ تا ۲۱۳ -->
<h2>هرجا باشید،<br/>مطب دست‌تان است</h2>
<h2>هرجا باشید،<br />مطب دست‌تان است</h2>
<p>روی گوشی، تبلت یا کامپیوتر بازش کنید؛ اطلاعات خودش هماهنگ می‌ماند ...</p>
```
@@ -73,7 +85,7 @@
- **همه‌ی** بخش‌های متنی صفحه را پوشش بده: nav، hero، feature columns، why band، devices، specialties (`پزشک عمومی`/`دندان‌پزشک`/`متخصص پوست`/`متخصص اطفال` و دو tick هرکدام)، app/desktop CTA (`کاملاً ایمن`/`نصب آسان`/`آپدیت رایگان`)، modal ثبت‌نام (`دکتر هستم`/...)، footer.
- اعداد و ادعاها را **باورپذیر** نگه‌دار (`+۵۰۰ مطب`, `۹۵٪ رضایت` می‌توانند بمانند یا کمی پانچی‌تر شوند، اما اغراق بی‌پایه نکن).
- آدرس/تلفن/ایمیل footer (`۰۷۴۹۱۰۱۲۱۷۸`، `info@clinic-pro.ir`، آدرس یاسوج) **دست‌نخورده** بماند.
- آدرس/تلفن/ایمیل footer (`02191550875`، `info@clinic-pro.ir`، آدرس یاسوج) **دست‌نخورده** بماند.
- لینک‌ها و `href`ها (`#hero`, `#features`, `/admin`, action مودال) عوض نشوند.
---
@@ -88,9 +100,17 @@
```html
<div class="nav-right">
<button class="nav-burger nav-toggle" id="navToggle" aria-label="منو">...</button>
<button class="btn btn-ghost" id="openRegModal" style="font-size:13px;padding:8px 20px">ثبت نام</button>
<a href="/admin" class="btn btn-blue" style="...">ورود به پنل</a>
<button class="nav-burger nav-toggle" id="navToggle" aria-label="منو">
...
</button>
<button
class="btn btn-ghost"
id="openRegModal"
style="font-size:13px;padding:8px 20px"
>
ثبت نام
</button>
<a href="/admin" class="btn btn-blue" style="...">ورود به پنل</a>
</div>
```
@@ -98,15 +118,22 @@
```css
@media (max-width: 640px) {
.nav-right #openRegModal { display: none; } /* در منوی موبایل می‌آید */
.nav-right { gap: 10px; }
.brand small { display: none; } /* «مدیریت مطب» را جا باز کن */
.nav-right #openRegModal {
display: none;
} /* در منوی موبایل می‌آید */
.nav-right {
gap: 10px;
}
.brand small {
display: none;
} /* «مدیریت مطب» را جا باز کن */
}
```
### مشکل ۲٫۲ — منوی موبایل با inline-style شکننده باز می‌شود و بسته نمی‌شود
در `home.html.twig` خط ۷۵۶ تا ۷۷۲، توگل منو با ست‌کردن مستقیم `navLinks.style.*` کار می‌کند (position/background/... دستی). این روش:
- با کلیک روی آیتم منو بسته نمی‌شود،
- دکمه‌های ثبت‌نام/ورود را شامل نمی‌شود،
- شکننده است.
@@ -114,23 +141,23 @@
**وضعیت فعلی:**
```js
var navToggle = document.getElementById('navToggle');
var navLinks = document.getElementById('navLinks');
var navToggle = document.getElementById("navToggle");
var navLinks = document.getElementById("navLinks");
if (navToggle)
navToggle.addEventListener('click', function () {
var open = navLinks.style.display === 'flex';
navLinks.style.display = open ? '' : 'flex';
if (!open) {
navLinks.style.position = 'absolute';
navLinks.style.top = '84px';
navLinks.style.insetInline = '0';
navLinks.style.flexDirection = 'column';
navLinks.style.background = '#fff';
navLinks.style.padding = '20px 32px';
navLinks.style.gap = '18px';
navLinks.style.boxShadow = '0 16px 30px oklch(0.4 0.08 285 / 0.1)';
}
});
navToggle.addEventListener("click", function () {
var open = navLinks.style.display === "flex";
navLinks.style.display = open ? "" : "flex";
if (!open) {
navLinks.style.position = "absolute";
navLinks.style.top = "84px";
navLinks.style.insetInline = "0";
navLinks.style.flexDirection = "column";
navLinks.style.background = "#fff";
navLinks.style.padding = "20px 32px";
navLinks.style.gap = "18px";
navLinks.style.boxShadow = "0 16px 30px oklch(0.4 0.08 285 / 0.1)";
}
});
```
**راه‌حل پیشنهادی:** منطق را به یک کلاس CSS منتقل کن (به‌جای inline-style) و با toggle کلاس کنترل کن؛ با کلیک روی هر لینک منو بسته شود.
@@ -138,15 +165,15 @@ if (navToggle)
JS تمیزتر:
```js
var navToggle = document.getElementById('navToggle');
var navLinks = document.getElementById('navLinks');
var navToggle = document.getElementById("navToggle");
var navLinks = document.getElementById("navLinks");
if (navToggle) {
navToggle.addEventListener('click', function () {
navLinks.classList.toggle('open');
});
navLinks.addEventListener('click', function (e) {
if (e.target.tagName === 'A') navLinks.classList.remove('open');
});
navToggle.addEventListener("click", function () {
navLinks.classList.toggle("open");
});
navLinks.addEventListener("click", function (e) {
if (e.target.tagName === "A") navLinks.classList.remove("open");
});
}
```
@@ -154,18 +181,20 @@ CSS متناظر در `styles.css` داخل `@media (max-width:640px)` (پنل d
```css
@media (max-width: 640px) {
.nav-links { display: none; }
.nav-links.open {
display: flex;
position: absolute;
top: 84px; /* ارتفاع هدر */
inset-inline: 0;
flex-direction: column;
gap: 18px;
background: #fff;
padding: 20px 32px;
box-shadow: 0 16px 30px oklch(0.4 0.08 285 / 0.1);
}
.nav-links {
display: none;
}
.nav-links.open {
display: flex;
position: absolute;
top: 84px; /* ارتفاع هدر */
inset-inline: 0;
flex-direction: column;
gap: 18px;
background: #fff;
padding: 20px 32px;
box-shadow: 0 16px 30px oklch(0.4 0.08 285 / 0.1);
}
}
```