user-app: extend the redesign across the account screens
Phase 2, completing the app-wide rollout of the home/product-detail design language (LESS colour tokens, BEM class names, hairline-bordered cards, SectionHead, dashed empty states) onto the account side: dashboard, orders, transactions, profile, login and register. Reuse over re-implementation: the dashboard's live rate block is now components/home/RateStrip.vue rather than a second hand-built strip, and every screen uses components/ui/PageBar.vue for its chrome. OrderCard and OrderItemCard are restyled to match. OrderItemCard drops its always-empty note row: our OrderItem schema has no note field (legacy's per-item note was a real column there; ours is not), so it could only ever print a dash. OrdersView swaps ant Tabs for the same scrolling chip rail the rest of the redesign uses, and its full-screen Modal with hand-written CSS overrides for a bottom Drawer, matching how every other detail surface opens. Deleted AppHeader.vue, orphaned once every screen moved to PageBar. Its shutter animation was driven by transitionFlag, which nothing reads any more — the router afterEach comment claiming otherwise is corrected rather than left asserting something untrue, and the now-inert half is flagged in place. ScrollFetchSearch loses its isFav prop: it gated two empty-state branches that rendered the identical image, and its only caller (FavoritesView) now renders its own. Behaviour is preserved throughout. Orders still reads GET /customers/:id/orders and filters client-side; transactions still reads GET /customers/:id/ledger-entries with legacy's CREDIT/DEBIT colour meaning intact; profile stays read-only over real fields; login keeps the real customer lookup plus the documented OTP stub; register stays stubbed with copy that does not claim an account was created. Verified in a real browser against the running API and native database: dashboard 4 tiles with a real balance, orders 1 real order card, profile 4 real spec rows, transactions the correct empty state for a customer with no ledger rows, and login/register confirmed with the session cleared (the guard bounces a signed-in user away from /login, which is why they needed a separate pass). No console errors, no horizontal overflow. vue-tsc and vite build both clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
cc62975dd0
commit
0e5f9ccd7b
@@ -1,110 +1,122 @@
|
||||
<!--
|
||||
Ported from legacy henza_pwa/src/views/user/src/components/Dashboard.vue —
|
||||
the most heavily adapted view in this port so far. Legacy's original (820
|
||||
lines) is a multi-role workbench mixing plain-customer, sales-agent
|
||||
("reagent"), and "banker" (type=1, sub-account switching) views. Kept: the
|
||||
real balance card, the nav grid to Orders/Documents/Profile/Favorites, and
|
||||
the logout/login-nudge dialogs — all backed by real data.
|
||||
Ported from legacy henza_pwa/src/views/user/src/components/Dashboard.vue,
|
||||
restyled into the redesigned design language (see components/home/* and
|
||||
HomeView). The live rate block now reuses components/home/RateStrip.vue
|
||||
rather than re-implementing the same strip a second time.
|
||||
|
||||
Legacy's original (820 lines) is a multi-role workbench mixing
|
||||
plain-customer, sales-agent ("reagent") and "banker" (type=1, sub-account
|
||||
switching) views. Kept: the real balance card, the nav grid to
|
||||
Orders/Documents/Profile/Favorites, and the logout/login-nudge dialogs —
|
||||
all backed by real data.
|
||||
|
||||
DROPPED as architecturally incompatible, not merely deferred: everything
|
||||
tied to legacy's `Customer.type`/multi-account model — "انتخاب مشتری"
|
||||
(toggleUser/hasActiveChild), "سفارش مشتریان" (ChildOrders), and
|
||||
customerChoice. In the redesigned schema (see the original migration
|
||||
audit), sales agents are AdminUser records with no customer-facing session
|
||||
at all — there is no "type" field on our Customer model, so there is
|
||||
nothing to adapt here; the underlying data model this UI assumed no longer
|
||||
exists.
|
||||
(toggleUser/hasActiveChild), "سفارش مشتریان" (ChildOrders) and
|
||||
customerChoice. Sales agents are AdminUser records with no customer-facing
|
||||
session at all, and there is no `type` field on our Customer model, so the
|
||||
data model this UI assumed no longer exists.
|
||||
|
||||
DROPPED as no backend exists: "سفارش ساخت" (custom/pre-order manufacturing)
|
||||
— PreOrder has a DB table but no controller anywhere in apps/api. Shown as
|
||||
a disabled tile rather than a broken link.
|
||||
— PreOrder has a DB table but no controller anywhere in apps/api.
|
||||
|
||||
REPLACED, not dropped: legacy's "گزارش حساب" van-action-sheet called out to
|
||||
the external Tahesab accounting service (hesabMe()) that the very first
|
||||
migration audit explicitly decided to retire in favor of this system's own
|
||||
internal ledger — this dashboard's balance card already shows that real,
|
||||
internal balance directly, so there's no separate popup needed.
|
||||
REPLACED, not dropped: legacy's "گزارش حساب" called out to the external
|
||||
Tahesab accounting service, which the first migration audit retired in
|
||||
favour of this system's own internal ledger — the balance card below shows
|
||||
that real internal position directly.
|
||||
|
||||
DROPPED: the multi-row world gold/currency price ticker (legacy's GET
|
||||
/price, ~14 rows). The new API has one single-karat quote endpoint
|
||||
(GET /pricing/latest) — shown as one line instead of fabricating rows that
|
||||
don't exist.
|
||||
DROPPED: the multi-row world gold/currency ticker (legacy's GET /price, ~14
|
||||
rows). The new API has one single-karat quote endpoint, shown as one strip
|
||||
rather than fabricating rows that don't exist.
|
||||
-->
|
||||
<template>
|
||||
<div class="fixed top-0 z-10 w-full">
|
||||
<AppHeader>
|
||||
<div class="flex justify-between items-center">
|
||||
<div></div>
|
||||
<h3 class="text-white bold mb-0 text-center w-full">میز کار</h3>
|
||||
<Icon v-if="session.customerId" icon="vuesax-linear:logout" @click="data.notify = true" class="cursor-pointer text-white absolute left-5" size="25" />
|
||||
<div class="dash">
|
||||
<header class="dash__bar">
|
||||
<div class="dash__barInner">
|
||||
<span class="dash__barSpacer" aria-hidden="true" />
|
||||
<h1 class="dash__barTitle">میز کار</h1>
|
||||
<button
|
||||
v-if="session.customerId"
|
||||
type="button"
|
||||
class="dash__barBtn"
|
||||
aria-label="خروج"
|
||||
@click="data.notify = true"
|
||||
>
|
||||
<Icon icon="vuesax-linear:logout" size="19" />
|
||||
</button>
|
||||
<span v-else class="dash__barSpacer" aria-hidden="true" />
|
||||
</div>
|
||||
</AppHeader>
|
||||
</div>
|
||||
<div class="h-16"></div>
|
||||
</header>
|
||||
|
||||
<container class="overflow-y-scroll pt-4">
|
||||
<div v-if="session.customerId">
|
||||
<div class="rounded-[10px] bg-[#F9F9F9] p-[16px] w-full mb-[16px] border-[#E5E7EB] border border-solid">
|
||||
<div class="grid grid-cols-5 items-center pb-2 mb-2 border-b-2 border-solid border-[#E5E7EB]">
|
||||
<h5 class="font-bold col-span-2 mb-0">{{ customer?.fullName }}</h5>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<div>شماره تلفن همراه</div>
|
||||
<div>{{ session.mobile }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="rounded-[10px] bg-[#F9F9F9] p-[16px] w-full mb-[16px] border-[#E5E7EB] border border-solid">
|
||||
<div class="text-center font-bold">برای استفاده از امکانات نرم افزار ابتدا وارد شوید</div>
|
||||
<div class="flex w-full justify-center mt-2" @click="router.push({ name: 'login' })">
|
||||
<Button type="primary" class="w-[17rem]">ورود/ثبت نام</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-[10px] bg-light p-[16px] w-full mb-[16px] bg-[#F9F9F9]" v-if="customer">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<div class="text-[12px] mb-2">{{ remainText }}</div>
|
||||
<div class="font-bold">{{ Math.abs(parseFloat(customer.goldDebtGrams)) }} گرم</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-[12px] mb-2">بدهی ریالی</div>
|
||||
<div class="font-bold">{{ priceUnit(customer.fiatDebtRial) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 gap-6 my-4">
|
||||
<div v-for="item in list" :key="item.id" class="grid col-span-1 cursor-pointer" @click="goToDetails(item.id)">
|
||||
<div class="border border-solid border-[#E5E7EB] bg-[#F9F9F9] rounded-[5px] flex justify-center items-center py-4" :class="{ 'opacity-40': item.disabled }">
|
||||
<Icon :icon="item.icon" />
|
||||
</div>
|
||||
<div class="text-center text-[14px] font-medium pt-2">{{ item.title }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-[10px] text-secondary col-span-6 mb-24" v-if="goldPrice">
|
||||
<div class="flex items-center justify-between bg-[#1C2D56] text-[#ffffff] p-3 rounded">
|
||||
<div class="font-bold text-[16px]">نرخ طلای ۱۸ عیار</div>
|
||||
<div>{{ jdate(goldPrice.quotedAt) }}</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 mt-2">
|
||||
<div class="bg-[#F9F9F9] rounded flex justify-between items-center p-2">
|
||||
<div class="flex items-center">
|
||||
<div class="bg-white rounded w-9 h-9 flex justify-center items-center">
|
||||
<Icon class="text-primary" icon="vuesax-linear:number-18" />
|
||||
<container class="dash__body">
|
||||
<!-- Signed in: real position from GET /customers/:id -->
|
||||
<template v-if="customer">
|
||||
<section class="dash__balance">
|
||||
<div class="dash__balanceHead">
|
||||
<div>
|
||||
<div class="dash__eyebrow">{{ remainText }}</div>
|
||||
<div class="dash__figure">
|
||||
{{ grams }}
|
||||
<span class="dash__unit">گرم</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-[#1C2D56] text-[15px] font-semibold mr-3">هر گرم طلای ۱۸ عیار</div>
|
||||
<span class="dash__seal" :class="isDebtor ? 'is-debtor' : 'is-creditor'">
|
||||
{{ isDebtor ? 'بدهکار' : 'بستانکار' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-[#1C2D56] text-[18px] font-semibold flex items-center">
|
||||
{{ price(goldPrice.pricePerGramRial) }}
|
||||
<div class="text-xs text-[#8D6A46] pr-0.5 font-medium">ریال</div>
|
||||
|
||||
<div class="dash__balanceRow">
|
||||
<span class="dash__rowLabel">بدهی ریالی</span>
|
||||
<span class="dash__rowValue">{{ price(customer.fiatDebtRial) }} <i>ریال</i></span>
|
||||
</div>
|
||||
|
||||
<div class="dash__identity">
|
||||
<span class="dash__name">{{ customer.fullName }}</span>
|
||||
<span class="dash__mobile">{{ session.mobile }}</span>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<!-- Signed out: a quiet invitation, no fabricated numbers -->
|
||||
<section v-else class="dash__invite">
|
||||
<div class="dash__inviteIcon" aria-hidden="true">
|
||||
<Icon icon="vuesax-linear:security-user" size="20" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dash__inviteCopy">
|
||||
<h3>حساب گرمی شما</h3>
|
||||
<p>برای دیدن موجودی، سفارشها و اسناد خود وارد شوید.</p>
|
||||
</div>
|
||||
<button type="button" class="dash__inviteCta" @click="router.push({ name: 'login' })">
|
||||
ورود / ثبتنام
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<!-- Nav grid -->
|
||||
<section class="dash__section">
|
||||
<SectionHead title="دسترسیها" subtitle="بخشهای حساب شما" />
|
||||
<div class="dash__grid">
|
||||
<button
|
||||
v-for="item in list"
|
||||
:key="item.id"
|
||||
type="button"
|
||||
class="dash__tile"
|
||||
:class="{ 'is-disabled': item.disabled }"
|
||||
@click="goToDetails(item.id)"
|
||||
>
|
||||
<span class="dash__tileIcon" aria-hidden="true">
|
||||
<Icon :icon="item.icon" size="20" />
|
||||
</span>
|
||||
<span class="dash__tileTitle">{{ item.title }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Live 18k rate — same strip the home screen uses -->
|
||||
<section class="dash__section">
|
||||
<SectionHead title="نرخ روز" subtitle="آخرین نرخ اعلامشده" />
|
||||
<RateStrip :quote="goldPrice" />
|
||||
</section>
|
||||
</container>
|
||||
|
||||
<DialogVant :timeOut="-1" v-model:show="data.notify" :closeOnClickOverlay="true">
|
||||
<template v-slot:img>
|
||||
@@ -116,32 +128,35 @@
|
||||
<div class="text-center text-[#6b7280]" @click="data.notify = false">بی خیال</div>
|
||||
</template>
|
||||
</DialogVant>
|
||||
|
||||
<DialogVant :timeOut="-1" v-model:show="data.loginNotify" :closeOnClickOverlay="true">
|
||||
<template v-slot:img>
|
||||
<img :src="loginDialogImage" alt="" class="opacity-80" />
|
||||
</template>
|
||||
<template v-slot:title>
|
||||
<div class="p-8 text-justify">برای دسترسی به تمامی امکانات نرم افزار هنزاگلد، ابتدا گزینه ورود/ثبت نام را لمس کنید و در صورت نداشتن حساب کاربری، ثبت نام نمایید.</div>
|
||||
<div class="p-8 text-justify">
|
||||
برای دسترسی به تمامی امکانات نرم افزار هنزاگلد، ابتدا گزینه ورود/ثبت نام را لمس کنید و در
|
||||
صورت نداشتن حساب کاربری، ثبت نام نمایید.
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:button>
|
||||
<div class="text-center text-[#1C2D56]" @click="router.push({ name: 'login' })">ورود/ثبت نام</div>
|
||||
<div class="text-center text-danger" @click="data.loginNotify = false">بیخیال</div>
|
||||
</template>
|
||||
</DialogVant>
|
||||
</container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { Button } from 'ant-design-vue'
|
||||
import Icon from '../../components/icon/Icon.vue'
|
||||
import AppHeader from '../../components/AppHeader.vue'
|
||||
import SectionHead from '../../components/home/SectionHead.vue'
|
||||
import RateStrip from '../../components/home/RateStrip.vue'
|
||||
import DialogVant from '../../components/DialogVant.vue'
|
||||
import exitImage from '../../assets/img/empty/dialogEmpty5.svg'
|
||||
import loginDialogImage from '../../assets/img/empty/dialogEmpty1.svg'
|
||||
import { price, priceUnit } from '../../utils/filters'
|
||||
import { jdate } from '../../utils/filters'
|
||||
import { price } from '../../utils/filters'
|
||||
import { useSessionStore } from '../../stores/session'
|
||||
import { api, type CustomerDetail, type GoldPriceQuote } from '../../api/client'
|
||||
|
||||
@@ -151,7 +166,14 @@ const session = useSessionStore()
|
||||
const customer = ref<CustomerDetail | null>(null)
|
||||
const goldPrice = ref<GoldPriceQuote | null>(null)
|
||||
|
||||
const remainText = computed(() => (customer.value && parseFloat(customer.value.goldDebtGrams) > 0 ? 'بدهکار گرمی' : 'بستانکار گرمی'))
|
||||
// The ledger stores the gram position as a signed figure — positive means the
|
||||
// customer owes gold. Labelled the same way AccountStrip does on the home
|
||||
// screen so the two never disagree.
|
||||
const isDebtor = computed(() => (customer.value ? parseFloat(customer.value.goldDebtGrams) > 0 : false))
|
||||
const remainText = computed(() => (isDebtor.value ? 'بدهکار گرمی' : 'بستانکار گرمی'))
|
||||
const grams = computed(() =>
|
||||
customer.value ? Math.abs(parseFloat(customer.value.goldDebtGrams)) : 0,
|
||||
)
|
||||
|
||||
const data = reactive({ notify: false, loginNotify: false })
|
||||
|
||||
@@ -190,3 +212,262 @@ onMounted(async () => {
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.dash {
|
||||
background: @canvas;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.dash__bar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 20;
|
||||
background: rgba(255, 255, 255, 0.88);
|
||||
backdrop-filter: blur(14px);
|
||||
border-bottom: 1px solid @hairline;
|
||||
}
|
||||
|
||||
.dash__barInner {
|
||||
max-width: 768px;
|
||||
margin: 0 auto;
|
||||
padding: 11px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.dash__barTitle {
|
||||
margin: 0;
|
||||
font-size: 14.5px;
|
||||
font-weight: 800;
|
||||
color: @ink;
|
||||
}
|
||||
|
||||
.dash__barBtn {
|
||||
flex: 0 0 auto;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
border-radius: 12px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: @wine;
|
||||
background: @wineWash;
|
||||
}
|
||||
|
||||
.dash__barBtn:active {
|
||||
transform: scale(0.94);
|
||||
}
|
||||
|
||||
.dash__barSpacer {
|
||||
display: block;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.dash__body {
|
||||
padding-top: 16px;
|
||||
padding-bottom: 90px;
|
||||
}
|
||||
|
||||
.dash__balance {
|
||||
padding: 16px;
|
||||
border-radius: 20px;
|
||||
background: @ink;
|
||||
color: #fff;
|
||||
box-shadow: 0 14px 30px -22px rgba(20, 22, 26, 0.95);
|
||||
}
|
||||
|
||||
.dash__balanceHead {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.dash__eyebrow {
|
||||
font-size: 11.5px;
|
||||
color: rgba(255, 255, 255, 0.62);
|
||||
}
|
||||
|
||||
.dash__figure {
|
||||
padding-top: 5px;
|
||||
font-size: 25px;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.3px;
|
||||
}
|
||||
|
||||
.dash__unit {
|
||||
font-size: 11.5px;
|
||||
font-weight: 600;
|
||||
color: rgba(255, 255, 255, 0.62);
|
||||
padding-inline-start: 4px;
|
||||
}
|
||||
|
||||
.dash__seal {
|
||||
flex: 0 0 auto;
|
||||
padding: 5px 12px;
|
||||
border-radius: 999px;
|
||||
font-size: 10.5px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.dash__seal.is-debtor {
|
||||
color: #fff;
|
||||
background: @wineSoft;
|
||||
}
|
||||
|
||||
.dash__seal.is-creditor {
|
||||
color: @ink;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.dash__balanceRow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-top: 16px;
|
||||
padding-top: 13px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.13);
|
||||
}
|
||||
|
||||
.dash__rowLabel {
|
||||
font-size: 11.5px;
|
||||
color: rgba(255, 255, 255, 0.62);
|
||||
}
|
||||
|
||||
.dash__rowValue {
|
||||
font-size: 13.5px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.dash__rowValue i {
|
||||
font-style: normal;
|
||||
font-size: 10.5px;
|
||||
font-weight: 600;
|
||||
color: rgba(255, 255, 255, 0.62);
|
||||
padding-inline-start: 3px;
|
||||
}
|
||||
|
||||
.dash__identity {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-top: 13px;
|
||||
padding-top: 13px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.13);
|
||||
}
|
||||
|
||||
.dash__name {
|
||||
font-size: 12.5px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.dash__mobile {
|
||||
font-size: 11.5px;
|
||||
color: rgba(255, 255, 255, 0.62);
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.dash__invite {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
border: 1px solid @hairline;
|
||||
border-radius: 20px;
|
||||
background: @canvasSoft;
|
||||
}
|
||||
|
||||
.dash__inviteIcon {
|
||||
flex: 0 0 42px;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 50%;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: @wine;
|
||||
background: @wineWash;
|
||||
}
|
||||
|
||||
.dash__inviteCopy {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.dash__inviteCopy h3 {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
color: @ink;
|
||||
}
|
||||
.dash__inviteCopy p {
|
||||
margin: 4px 0 0;
|
||||
font-size: 11.5px;
|
||||
color: @inkFaint;
|
||||
}
|
||||
|
||||
.dash__inviteCta {
|
||||
flex: 0 0 auto;
|
||||
padding: 9px 14px;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
border-radius: 999px;
|
||||
font-family: inherit;
|
||||
font-size: 11.5px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
background: @ink;
|
||||
}
|
||||
|
||||
.dash__section {
|
||||
margin-top: 26px;
|
||||
}
|
||||
|
||||
.dash__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 9px;
|
||||
}
|
||||
|
||||
.dash__tile {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 14px 6px;
|
||||
border: 1px solid @hairline;
|
||||
border-radius: 16px;
|
||||
cursor: pointer;
|
||||
background: @canvas;
|
||||
font-family: inherit;
|
||||
transition: transform 0.18s ease;
|
||||
}
|
||||
|
||||
.dash__tile:active {
|
||||
transform: scale(0.97);
|
||||
}
|
||||
|
||||
.dash__tile.is-disabled {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.dash__tileIcon {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border-radius: 12px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: @inkSoft;
|
||||
background: @hairlineSoft;
|
||||
}
|
||||
|
||||
.dash__tileTitle {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
color: @inkSoft;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user