Files
tehran_taj/apps/admin-panel/src/App.vue
T
s.esmaeiliandClaude Haiku 5.5 532ceee189 feat: move brand name to one config and redesign the accounting card
اپ: نام برند در همه‌ی صفحه‌ها و پیام‌ها یکسان شده و از یک تنظیم مرکزی خوانده می‌شود.
اپ: کارت حسابداری در صفحه‌ی مشتری بازطراحی شد؛ مانده‌ها و وضعیت لینک واضح‌تر نمایش داده می‌شوند.
پنل: کارت حسابداری در پرونده‌ی مشتری بازطراحی شد؛ مانده‌ها، آخرین ارسال و فرم لینک دستی واضح‌تر شده‌اند.
پنل: ستون «کد» در جدول‌ها به‌طور پیش‌فرض پنهان است و از انتخاب ستون‌ها قابل نمایش است.
پنل: تغییر نمایش ستون‌ها در جدول‌ها بلافاصله اعمال می‌شود.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-14 13:31:20 +03:30

124 lines
4.7 KiB
Vue

<template>
<!--
ConfigProvider supplies ant-design-vue's OWN strings and text direction.
Without it ant rendered its built-in copy — pagination ("items/page"), table
filter menus ("Reset"/"OK"), Select's "No Data", Popconfirm's default
buttons — in ENGLISH inside an otherwise fully Farsi RTL panel.
NOTE this covers ant's own chrome only. Jalali dates still come from
moment-jalaali via components/input/DateInput.vue, which is unaffected.
`:theme` replaces the old vite.config.ts LESS `modifyVars` (ant-design-vue 4
dropped LESS theming for CSS-in-JS design tokens). Only the three legacy
variables that ant itself ever consumed are carried over — `secondary-color`
and `third-color` were never real ant variables (confirmed dead in the old
LESS build) and stay only as the CSS custom properties in utilities.less.
ant derives its light "primary background" steps from colorPrimary; for a
navy this dark the generated steps are mid-greys (#8d9296, #81858a), which
painted every selected option / tree node / picker cell grey. Those steps
are pinned to light navy tints instead (see `themeTokens`).
-->
<a-config-provider :locale="faIR" direction="rtl" :theme="{ token: themeTokens }">
<div id="app" :class="vueAppClasses">
<router-view @setAppClasses="setAppClasses" />
<AppUpdateGate />
</div>
</a-config-provider>
</template>
<script setup lang="ts">
// Ported from legacy henza_admin/src/App.vue.
// Dropped (Vue-2-only or dead in legacy): the VeeValidate Farsi dictionary (`$validator`
// has no Vue 3 equivalent and validation is re-done per-form with ant-design-vue rules),
// the commented-out Firebase/service-worker block, and the `$vs.rtl` watcher (Vuesax).
// RTL now comes from themeConfig.rtl directly, which is the same value legacy fed Vuesax.
import { onMounted, onUnmounted, ref, watch } from 'vue';
import { notification } from 'ant-design-vue';
import faIR from 'ant-design-vue/es/locale/fa_IR';
import themeConfig from './themeConfig';
import { brand } from './brand';
import { useLayoutStore } from './stores/layout';
import AppUpdateGate from './components/common/AppUpdateGate.vue';
import { userName } from './utils';
const themeTokens = {
colorPrimary: '#1c2d56',
colorLink: '#1DA57A',
borderRadius: 6,
controlHeight: 36,
colorPrimaryBg: '#eef1f8',
colorPrimaryBgHover: '#e1e6f2',
colorPrimaryBorder: '#c5cde0',
colorPrimaryBorderHover: '#9ea9c6',
};
const layout = useLayoutStore();
const vueAppClasses = ref<string[]>([]);
function toggleClassInBody(className: string) {
if (className === 'dark') {
if (document.body.className.match('theme-semi-dark')) document.body.classList.remove('theme-semi-dark');
document.body.classList.add('theme-dark');
} else if (className === 'semi-dark') {
if (document.body.className.match('theme-dark')) document.body.classList.remove('theme-dark');
document.body.classList.add('theme-semi-dark');
} else {
if (document.body.className.match('theme-dark')) document.body.classList.remove('theme-dark');
if (document.body.className.match('theme-semi-dark')) document.body.classList.remove('theme-semi-dark');
}
}
function setAppClasses(classesStr: string) {
vueAppClasses.value.push(classesStr);
}
function handleWindowResize() {
layout.updateWindowWidth(window.innerWidth);
// Set --vh property
document.documentElement.style.setProperty('--vh', `${window.innerHeight * 0.01}px`);
}
function handleScroll() {
layout.updateWindowScrollY(window.scrollY);
}
watch(() => layout.theme, (val) => toggleClassInBody(val));
// legacy created(): set dir before first paint
document.documentElement.setAttribute('dir', themeConfig.rtl ? 'rtl' : 'ltr');
onMounted(() => {
// legacy showed a one-shot welcome toast when a `login` flag was left in localStorage
const rawUser = localStorage.getItem(userName);
const user = rawUser ? JSON.parse(rawUser) : undefined;
const login = localStorage.getItem('login') || undefined;
if (user && login) {
notification.open({
message: `${user && user.name ? user.name : ' کاربر '} عزیز `,
placement: 'topLeft',
description: `به ${brand.name} خوش آمدید`,
style: {
color: 'var(--primary-color)',
marginLeft: `20px`,
},
});
localStorage.removeItem('login');
}
toggleClassInBody(themeConfig.theme);
layout.updateWindowWidth(window.innerWidth);
const vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
window.addEventListener('resize', handleWindowResize);
window.addEventListener('scroll', handleScroll);
});
onUnmounted(() => {
window.removeEventListener('resize', handleWindowResize);
window.removeEventListener('scroll', handleScroll);
});
</script>