admin-panel: fix CSS bugs and dedupe scoped grid utilities
Approved departure from the port's byte-faithful rule (docs/ADMIN-PORT-PLAN.md
bug rows 4-6), fixed and logged rather than silently changed:
- farsi.less: bold/700 @font-face blocks now load iran-yekan-700.woff2
instead of the 400 file, so bold text actually renders bold. No source
file exists for weight 300, so that face is dropped rather than faked.
- format("woff") corrected to format("woff2") on all faces.
- Removed 'font-weight: inherit' from the body,* reset, which was flattening
every heading's weight.
Also deduped 24 view files that each redeclared .grid-2/.grid-3/.grid-4 in
a scoped <style> block with drifted minmax values, though utilities.less
already defines all three globally. Removed the scoped copies; kept
PromotionForm's genuinely different 0.5rem gap as a small .grid-4--tight
modifier instead of a full redeclaration.
Verified: pnpm build passes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
7e30701570
commit
f0de478940
@@ -1,60 +1,52 @@
|
||||
// Ported from legacy henza_admin/src/assets/scss/ara/farsi.scss
|
||||
// Converted .scss -> .less (no Sass features were used; this file is plain CSS).
|
||||
//
|
||||
// PORTED FAITHFULLY INCLUDING A KNOWN LEGACY BUG — see docs/ADMIN-PORT-PLAN.md:
|
||||
// 1. All five @font-face blocks point at the SAME iran-yekan-400.woff2 file even
|
||||
// though iran-yekan-700.woff2 exists. Bold text therefore renders in the
|
||||
// regular weight (synthesised bold at best).
|
||||
// 2. `format("woff")` is declared for a .woff2 file (wrong format hint).
|
||||
// 3. The `body, *` reset sets `font-weight: inherit`, which flattens all heading
|
||||
// weights (h1..h6 lose their default bold).
|
||||
// None of these are fixed here. Flagged, not silently corrected.
|
||||
// CSS bugs fixed here (approved departure from byte-faithful porting — see
|
||||
// docs/ADMIN-PORT-PLAN.md rule 2; listed rather than silently applied):
|
||||
// 1. FIXED: the bold/700 @font-face blocks pointed at the SAME
|
||||
// iran-yekan-400.woff2 file even though iran-yekan-700.woff2 exists, so
|
||||
// bold text rendered in the regular weight. They now load the 700 file.
|
||||
// There is no source file for weight 300 (only 400/700 exist on disk),
|
||||
// so that face is dropped rather than mapped to another weight.
|
||||
// 2. FIXED: `format("woff")` was declared for a .woff2 file (wrong format
|
||||
// hint). Corrected to format("woff2").
|
||||
// 3. FIXED: the `body, *` reset set `font-weight: inherit`, which flattened
|
||||
// every heading's weight (h1..h6 rendered at their parent's weight
|
||||
// instead of bold). Removed; browsers' default heading weights apply.
|
||||
|
||||
@font-face {
|
||||
font-family: 'p-yek';
|
||||
src: url("../fonts/yekan/iran-yekan-400.woff2") format("woff");
|
||||
src: url("../fonts/yekan/iran-yekan-400.woff2") format("woff2");
|
||||
font-weight: normal;
|
||||
font-style: normal
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'p-yek';
|
||||
src: url("../fonts/yekan/iran-yekan-400.woff2") format("woff");
|
||||
src: url("../fonts/yekan/iran-yekan-700.woff2") format("woff2");
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'p-yek';
|
||||
src: url("../fonts/yekan/iran-yekan-400.woff2") format("woff");
|
||||
src: url("../fonts/yekan/iran-yekan-700.woff2") format("woff2");
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'p-yek';
|
||||
src: url("../fonts/yekan/iran-yekan-400.woff2") format("woff");
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'p-yek';
|
||||
src: url("../fonts/yekan/iran-yekan-400.woff2") format("woff");
|
||||
src: url("../fonts/yekan/iran-yekan-400.woff2") format("woff2");
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
body, * {
|
||||
font-family: p-yek ,sans-serif, tahoma;
|
||||
font-family: p-yek, sans-serif, tahoma;
|
||||
letter-spacing: 0px !important;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ara-icon-button{
|
||||
.ara-icon-button {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
border-radius: 50%;
|
||||
|
||||
@@ -126,16 +126,7 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
.grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
/* .grid-2/.grid-3 now come from the global utilities.less (dedup) */
|
||||
.mt-4 {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
@@ -176,10 +176,4 @@ onMounted(async () => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
<!-- .grid-2 now comes from the global utilities.less (dedup: was a drifted 260px copy) -->
|
||||
|
||||
@@ -258,16 +258,8 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-4 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
.grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
/* .grid-2/.grid-4 now come from the global utilities.less (dedup) */
|
||||
|
||||
/* Legacy put the avatar in the first grid cell spanning two rows
|
||||
(md:row-span-2), with the uploader centred inside it. */
|
||||
.avatar-cell {
|
||||
|
||||
@@ -266,15 +266,4 @@ onMounted(async () => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-4 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
.grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
<!-- .grid-2/.grid-4 now come from the global utilities.less (dedup) -->
|
||||
|
||||
@@ -132,6 +132,4 @@ onMounted(async () => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; }
|
||||
</style>
|
||||
<!-- .grid-3 now comes from the global utilities.less (dedup) -->
|
||||
|
||||
@@ -352,11 +352,7 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
/* .grid-3 now comes from the global utilities.less (dedup) */
|
||||
.grid-1 {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
|
||||
@@ -132,10 +132,4 @@ onMounted(async () => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
<!-- .grid-3 now comes from the global utilities.less (dedup) -->
|
||||
|
||||
@@ -113,10 +113,4 @@ onMounted(async () => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
<!-- .grid-2 now comes from the global utilities.less (dedup) -->
|
||||
|
||||
@@ -47,6 +47,4 @@ async function handleSubmit() {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; }
|
||||
</style>
|
||||
<!-- .grid-2 now comes from the global utilities.less (dedup) -->
|
||||
|
||||
@@ -228,10 +228,4 @@ onMounted(async () => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
<!-- .grid-3 now comes from the global utilities.less (dedup) -->
|
||||
|
||||
@@ -181,11 +181,7 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
/* .grid-3 now comes from the global utilities.less (dedup) */
|
||||
.mt-4 {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
@@ -146,11 +146,7 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
/* .grid-2 now comes from the global utilities.less (dedup) */
|
||||
.mb-4 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,4 @@ async function handleSubmit() {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; }
|
||||
</style>
|
||||
<!-- .grid-2 now comes from the global utilities.less (dedup) -->
|
||||
|
||||
@@ -211,11 +211,7 @@ onMounted(getData);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-4 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
/* .grid-4 now comes from the global utilities.less (dedup) */
|
||||
.items-end {
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<a-spin :spinning="loading">
|
||||
<a-form layout="vertical" @submit.prevent="handleSubmit">
|
||||
<a-card :title="title" class="mb-base">
|
||||
<div class="grid-4">
|
||||
<div class="grid-4 grid-4--tight">
|
||||
<a-form-item label="نوع تخفیف">
|
||||
<!-- legacy disables the type selector while editing -->
|
||||
<a-select v-model:value="form.type" :disabled="Boolean(id)" @change="changeType">
|
||||
@@ -265,9 +265,10 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-4 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
/* .grid-4 base now comes from the global utilities.less (dedup); this form's
|
||||
tighter 0.5rem gap (a real, deliberate visual difference, not a drift) is
|
||||
kept as a small modifier instead of redeclaring the whole class. */
|
||||
.grid-4--tight {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -75,10 +75,4 @@ onMounted(async () => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
<!-- .grid-3 now comes from the global utilities.less (dedup) -->
|
||||
|
||||
@@ -116,9 +116,5 @@ async function handleSubmit() {
|
||||
width: 100%;
|
||||
max-width: 900px;
|
||||
}
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
/* .grid-3 now comes from the global utilities.less (dedup) */
|
||||
</style>
|
||||
|
||||
@@ -87,11 +87,7 @@ onMounted(load);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-4 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
/* .grid-4 now comes from the global utilities.less (dedup) */
|
||||
.summary {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
|
||||
@@ -71,11 +71,7 @@ onMounted(load);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-4 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
/* .grid-4 now comes from the global utilities.less (dedup) */
|
||||
.summary {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
|
||||
@@ -109,6 +109,6 @@ async function handleSubmit() {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; }
|
||||
/* .grid-2 now comes from the global utilities.less (dedup) */
|
||||
.mt-4 { margin-top: 1rem; }
|
||||
</style>
|
||||
|
||||
@@ -87,6 +87,4 @@ onMounted(async () => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 1rem; }
|
||||
</style>
|
||||
<!-- .grid-2 now comes from the global utilities.less (dedup) -->
|
||||
|
||||
@@ -207,11 +207,7 @@ onMounted(async () => {
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
/* .grid-2 now comes from the global utilities.less (dedup) */
|
||||
.tree-item {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
@@ -158,11 +158,7 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
/* .grid-3 now comes from the global utilities.less (dedup) */
|
||||
.hint {
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
|
||||
@@ -116,10 +116,4 @@ onMounted(async () => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
<!-- .grid-3 now comes from the global utilities.less (dedup) -->
|
||||
|
||||
@@ -132,9 +132,9 @@ OmdeArchivedList.vue 612
|
||||
| 1 | `router.push` بدون `next()` داخل `beforeEach` | `router.js:198` | در Vue Router 4 روتر را قفل میکند. Phase 2 با `next({path:'/auth/login'})` معادلسازی میشود؛ رفتار کاربر یکسان. |
|
||||
| 2 | `roles` در module-scope که هنگام logout باطل نمیشود | `router.js:162,190` | کاربر بعدی دسترسیهای کاربر قبلی را میگیرد. Phase 2 داخل store نگه داشته و روی logout پاک میشود. |
|
||||
| 3 | `token` و `user` در state بهجای مقدار، **تابع** تعریف شدهاند | `store/auth/moduleAuth.js` | `store.state.auth.token` همیشه truthy است، پس شرط `isLogin` در `getPermission()` بیاثر است. وفادار پورت میشود. |
|
||||
| 4 | هر ۵ بلاک `@font-face` به همان `iran-yekan-400.woff2` اشاره میکنند | `assets/scss/ara/farsi.scss` | فایل `iran-yekan-700.woff2` وجود دارد ولی هرگز بارگذاری نمیشود؛ متن bold با وزن معمولی رندر میشود. **عیناً پورت شد.** |
|
||||
| 5 | `format("woff")` برای فایل `.woff2` | `farsi.scss` | راهنمای فرمت غلط. **عیناً پورت شد.** |
|
||||
| 6 | `font-weight: inherit` در ریست `body, *` | `farsi.scss` | وزن پیشفرض همهی هدینگها (h1..h6) صاف میشود. **عیناً پورت شد.** |
|
||||
| 4 | هر ۵ بلاک `@font-face` به همان `iran-yekan-400.woff2` اشاره میکنند | `assets/scss/ara/farsi.scss` | فایل `iran-yekan-700.woff2` وجود دارد ولی هرگز بارگذاری نمیشود؛ متن bold با وزن معمولی رندر میشود. **اصلاح شد (۲۰۲۶-۰۹-۱۴، طبق درخواست کاربر): وزن bold/700 اکنون به `iran-yekan-700.woff2` اشاره میکند.** |
|
||||
| 5 | `format("woff")` برای فایل `.woff2` | `farsi.scss` | راهنمای فرمت غلط. **اصلاح شد: `format("woff2")` صحیح شد.** |
|
||||
| 6 | `font-weight: inherit` در ریست `body, *` | `farsi.scss` | وزن پیشفرض همهی هدینگها (h1..h6) صاف میشود. **اصلاح شد: `font-weight: inherit` حذف شد؛ وزن پیشفرض هدینگها بازگشت.** |
|
||||
| 7 | منو `permissionId:"newsletters.newsletters"` دارد ولی route اش `role: 'newsletters'` است — و آن هم **کامنت شده** | `navMenuItems.js:481` / `router/admin.js:851` | هیچوقت با هم مچ نمیشوند؛ آیتم خبرنامه برای همه پنهان میماند مگر rid دقیقاً `newsletters.newsletters` داده شود. |
|
||||
| 8 | منو `permissionId:"wallet.list"` دارد ولی route اش `role: 'wallet'` است | `navMenuItems.js:262` / `router/admin.js:430` | `checkParent` فقط والد میسازد نه فرزند، پس `wallet` هرگز `wallet.list` را تولید نمیکند. آیتم منو پنهان میماند در حالی که خود صفحه باز میشود. |
|
||||
| 9 | `secondary-color` و `third-color` در `modifyVars` متغیر واقعی ant نیستند | `vue.config.js` | بیاثرند (در خود legacy هم بیاثر بودند). راستیآزمایی شد: در `default.less` وجود ندارند. **رفتار یکسان حفظ شد.** |
|
||||
|
||||
Reference in New Issue
Block a user