Files
tehran_taj/apps/user-app-v2/src/views/user/AppearanceView.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

342 lines
8.8 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
تنظیمات ظاهری — the colour theme and the "fast & light" motion switch.
Reached from the dashboard; open to signed-out users too (these are device
preferences, not account data). State lives in stores/appearanceStore.ts,
which applies it to <html> immediately — nothing to save or confirm.
The theme previews are drawn with FIXED colours, not theme tokens: each one
has to show what that theme looks like, whichever theme is active now.
STRUCTURE IS SHARED, LOOK IS NOT: template and script are identical in
user-app and user-app-v2; only the "Look" block differs, per app.
-->
<template>
<div class="ap">
<PageBar title="تنظیمات ظاهری" back-to="userPage::hasSubRoute" />
<container class="ap__body">
<!-- ── Theme ───────────────────────────────────────────── -->
<section class="ap__section">
<header class="ap__head">
<h2 id="ap-theme" class="ap__title">پوسته برنامه</h2>
<p class="ap__sub">ظاهر روشن یا تیره، یا هماهنگ با تنظیمات گوشی شما</p>
</header>
<div class="ap__themes" role="radiogroup" aria-labelledby="ap-theme">
<button
v-for="opt in THEMES"
:key="opt.value"
type="button"
role="radio"
class="ap__theme"
:class="{ 'is-on': appearance.theme === opt.value }"
:aria-checked="appearance.theme === opt.value"
@click="appearance.setTheme(opt.value)"
>
<span class="ap__preview" :class="`ap__preview--${opt.value}`" aria-hidden="true">
<span class="ap__pvBar"></span>
<span class="ap__pvCard"></span>
<span class="ap__pvLine"></span>
<span class="ap__pvLine ap__pvLine--short"></span>
<span class="ap__pvBtn"></span>
</span>
<span class="ap__themeLabel">
<Icon :icon="opt.icon" size="15" />
{{ opt.label }}
</span>
<span class="ap__check" aria-hidden="true">
<Icon icon="vuesax-linear:tick-circle" size="18" />
</span>
</button>
</div>
<p v-if="appearance.theme === 'system'" class="ap__note">
الان {{ appearance.resolvedTheme === 'dark' ? 'تیره' : 'روشن' }} است، مطابق تنظیمات گوشی.
</p>
</section>
<!-- ── Motion ──────────────────────────────────────────── -->
<section class="ap__section">
<header class="ap__head">
<h2 class="ap__title">انیمیشن‌ها</h2>
<p class="ap__sub">برای سرعت بیشتر روی گوشی‌های ضعیف‌تر</p>
</header>
<!-- The whole row is the switch: one tap target, one announcement. -->
<button
type="button"
role="switch"
class="ap__row"
:aria-checked="appearance.reduceMotion"
@click="appearance.setReduceMotion(!appearance.reduceMotion)"
>
<span class="ap__rowIcon" aria-hidden="true">
<Icon icon="vuesax-linear:flash" size="18" />
</span>
<span class="ap__rowText">
<b>حالت سبک و سریع</b>
<small>
حرکت‌های سنگین، افکت‌های شیشه‌ای و اسلاید خودکار خاموش می‌شوند؛ بازخورد کوتاه لمس‌ها و جابه‌جایی‌های سریع
باقی می‌مانند تا برنامه خشک و بی‌روح نشود.
</small>
</span>
<ToggleSwitch :on="appearance.reduceMotion" />
</button>
</section>
</container>
</div>
</template>
<script setup lang="ts">
import Icon from '../../components/icon/Icon.vue'
import PageBar from '../../components/ui/PageBar.vue'
import ToggleSwitch from '../../components/ui/ToggleSwitch.vue'
import { useAppearanceStore, type ThemeChoice } from '../../stores/appearanceStore'
const appearance = useAppearanceStore()
const THEMES: { value: ThemeChoice; label: string; icon: string }[] = [
{ value: 'light', label: 'روشن', icon: 'vuesax-linear:sun-1' },
{ value: 'dark', label: 'تیره', icon: 'vuesax-linear:moon' },
{ value: 'system', label: 'مطابق سیستم', icon: 'vuesax-linear:monitor-mobbile' },
]
</script>
<style scoped lang="less">
/* ── Structure (same in both apps) ──────────────────────────── */
.ap {
min-height: 100vh;
}
.ap__body {
padding-top: 76px;
padding-bottom: 90px;
display: flex;
flex-direction: column;
gap: 26px;
}
.ap__title,
.ap__sub,
.ap__note {
margin: 0;
}
.ap__themes {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 10px;
}
.ap__theme {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
cursor: pointer;
font-family: inherit;
-webkit-tap-highlight-color: transparent;
transition: transform 0.15s ease, border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
}
.ap__theme:active {
transform: scale(0.97);
}
.ap__themeLabel {
display: inline-flex;
align-items: center;
gap: 5px;
white-space: nowrap;
}
.ap__check {
position: absolute;
top: 8px;
inset-inline-end: 8px;
display: grid;
place-items: center;
opacity: 0;
transform: scale(0.6);
transition: opacity 0.18s ease, transform 0.22s cubic-bezier(0.32, 0.72, 0, 1);
}
.ap__theme.is-on .ap__check {
opacity: 1;
transform: none;
}
// Mini screen, fixed colours on purpose (see the header).
.ap__preview {
position: relative;
width: 100%;
aspect-ratio: 3 / 4;
overflow: hidden;
display: flex;
flex-direction: column;
gap: 6%;
padding: 10% 12%;
--pv-bg: #ffffff;
--pv-bar: #f4f5f6;
--pv-card: #ecedef;
--pv-line: #dadce0;
--pv-btn: #14161a;
background: var(--pv-bg);
}
.ap__preview--dark {
--pv-bg: #16171a;
--pv-bar: #1e2024;
--pv-card: #2b2e34;
--pv-line: #3a3e45;
--pv-btn: #f1f2f4;
}
// System: the light screen with its lower-left half in dark.
.ap__preview--system::after {
content: '';
position: absolute;
inset: 0;
background: #16171a;
clip-path: polygon(100% 0, 100% 100%, 0 100%);
opacity: 0.94;
}
.ap__pvBar {
height: 9%;
border-radius: 4px;
background: var(--pv-bar);
}
.ap__pvCard {
flex: 1;
border-radius: 7px;
background: var(--pv-card);
}
.ap__pvLine {
height: 6%;
border-radius: 3px;
background: var(--pv-line);
}
.ap__pvLine--short {
width: 60%;
}
.ap__pvBtn {
height: 11%;
border-radius: 999px;
background: var(--pv-btn);
}
.ap__row {
width: 100%;
display: flex;
align-items: center;
gap: 12px;
cursor: pointer;
font-family: inherit;
text-align: start;
-webkit-tap-highlight-color: transparent;
transition: transform 0.15s ease, border-color 0.2s ease;
}
.ap__row:active {
transform: scale(0.985);
}
.ap__rowIcon {
flex: 0 0 auto;
display: grid;
place-items: center;
}
.ap__rowText {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 3px;
}
/* ── Look: user-app-v2 ──────────────────────────────────────── */
// Borderless @hairlineSoft panels at the 22px radius, chosen = an @ink ring
// with a filled @ink check (the app's chips); the motion row is the
// dashboard's own settings row, wine icon tile and all.
.ap {
background: @page;
}
.ap__head {
margin-bottom: 12px;
}
.ap__title {
font-size: 16px;
font-weight: 700;
color: @ink;
}
.ap__sub {
margin-top: 4px;
font-size: 11.5px;
color: @inkFaint;
}
.ap__note {
margin-top: 10px;
font-size: 11.5px;
color: @inkMuted;
}
.ap__theme {
padding: 10px 10px 12px;
border: 0;
border-radius: 22px;
background: @hairlineSoft;
color: @inkMuted;
box-shadow: inset 0 0 0 1.5px transparent;
}
.ap__theme.is-on {
color: @ink;
box-shadow: inset 0 0 0 1.5px @wine;
}
.ap__preview {
border-radius: 14px;
box-shadow: 0 0 0 1px rgba(20, 22, 26, 0.06);
}
.ap__themeLabel {
font-size: 12px;
font-weight: 700;
}
.ap__check {
width: 22px;
height: 22px;
border-radius: 50%;
color: #fff;
background: @wine;
}
.ap__row {
padding: 13px 14px;
border: 1px solid @hairline;
border-radius: 17px;
background: @canvas;
}
.ap__row:active {
border-color: alpha(@wine, 20%);
}
.ap__rowIcon {
width: 38px;
height: 38px;
border-radius: 12px;
color: @wine;
background: @wineWash;
}
.ap__rowText b {
font-size: 12.5px;
font-weight: 700;
color: @ink;
}
.ap__rowText small {
font-size: 10.5px;
line-height: 1.9;
color: @inkFaint;
}
</style>