Refine profile cards layout and styling

This commit is contained in:
Ruslan Bakiev
2026-04-03 12:06:04 +07:00
parent 12fbe00ee2
commit 71d2b176e9
6 changed files with 75 additions and 49 deletions

View File

@@ -40,7 +40,7 @@
--radius-box: 2rem;
--size-selector: 0.3125rem;
--size-field: 0.3125rem;
--border: 1px;
--border: 0px;
--depth: 0;
--noise: 1;
}
@@ -106,7 +106,12 @@ body {
.surface-card {
border: 0;
background: #fff;
box-shadow: 0 14px 32px rgba(24, 66, 44, 0.08);
box-shadow: none;
transition: box-shadow 0.2s ease;
}
.surface-card:hover {
box-shadow: 0 14px 32px rgba(24, 66, 44, 0.1);
}
.fregat-header-glass {

View File

@@ -135,7 +135,7 @@ async function submitCart() {
<section class="space-y-6">
<h1 class="text-3xl font-extrabold text-[#0f2f20]">Корзина</h1>
<div v-if="counterpartyLoading" class="alert surface-card border-0">
<div v-if="counterpartyLoading" class="alert surface-card">
Проверяем карточку контрагента...
</div>
<div v-else-if="!isCounterpartyComplete" class="alert alert-warning">
@@ -146,7 +146,7 @@ async function submitCart() {
<div class="surface-card rounded-3xl p-4 md:p-5">
<h2 class="text-lg font-bold text-[#123824]">Адрес доставки</h2>
<div v-if="deliveryAddressesQuery.loading" class="alert mt-3 surface-card border-0">
<div v-if="deliveryAddressesQuery.loading" class="alert mt-3 surface-card">
Загружаем адреса...
</div>
<div v-else-if="!hasDeliveryAddresses" class="alert alert-warning mt-3">
@@ -157,7 +157,7 @@ async function submitCart() {
<label
v-for="address in deliveryAddresses"
:key="address.id"
class="flex cursor-pointer items-start gap-3 rounded-2xl border border-[#d6ebde] bg-white/75 p-3"
class="flex cursor-pointer items-start gap-3 rounded-2xl bg-white p-3 transition hover:shadow-md"
>
<input
v-model="selectedDeliveryAddressId"
@@ -179,7 +179,7 @@ async function submitCart() {
<h2 class="text-xl font-bold text-[#123824]">Позиции</h2>
<div v-if="cartItems.length === 0" class="alert surface-card border-0">
<div v-if="cartItems.length === 0" class="alert surface-card">
Корзина пока пустая. Добавьте товар из каталога.
</div>
@@ -226,7 +226,7 @@ async function submitCart() {
</div>
<button
class="btn w-full border-0 bg-[#139957] text-white hover:bg-[#0d854a]"
class="btn w-full bg-[#139957] text-white hover:bg-[#0d854a]"
:disabled="sending || counterpartyLoading || !isCounterpartyComplete || !selectedDeliveryAddressId || cartItems.length === 0"
@click="submitCart"
>

View File

@@ -39,14 +39,15 @@ const maxConnected = computed(() =>
const connectedMessengerCount = computed(() => Number(telegramConnected.value) + Number(maxConnected.value));
const companyNamePreview = computed(() => profileQuery.result.value?.myCounterpartyProfile?.companyName?.trim() || '');
const notificationsSummary = computed(() => {
if (connectedMessengerCount.value === 0) {
return 'Уведомления не подключены. Подключите Telegram и Max для удобной работы с заказами.';
return 'Подключите Telegram и Max, чтобы получать статусы заказов и важные уведомления.';
}
if (connectedMessengerCount.value === 1) {
return 'Подключен 1 канал. Рекомендуем подключить второй канал как резервный.';
return 'Подключен один канал. Добавьте второй канал для резервного уведомления.';
}
return 'Оба канала подключены. Вы будете получать уведомления в Telegram и Max.';
return 'Оба канала подключены. Уведомления будут приходить в Telegram и Max.';
});
const deliveryAddresses = computed<DeliveryAddressItem[]>(() => deliveryAddressesQuery.result.value?.myDeliveryAddresses ?? []);
@@ -58,32 +59,52 @@ const defaultDeliveryAddress = computed(() => deliveryAddresses.value.find((item
<h1 class="text-3xl font-extrabold text-[#0f2f20]">Профиль</h1>
<div class="grid gap-4 md:grid-cols-3">
<NuxtLink to="/profile/counterparty" class="block rounded-3xl border border-[#d6ebde] bg-[#f7fffb] p-5 transition hover:shadow-md">
<p class="text-sm opacity-70">Карточка контрагента</p>
<p class="mt-2 text-lg font-bold text-[#123824]">{{ profileIsComplete ? 'Заполнена' : 'Требует внимания' }}</p>
<p class="mt-2 text-sm text-[#355947]">
<NuxtLink to="/profile/counterparty" class="block rounded-3xl bg-white p-5 transition hover:shadow-md">
<div class="mb-2 flex items-start justify-between gap-2">
<p class="text-lg font-bold text-[#123824]">Карточка контрагента</p>
<span v-if="!profileIsComplete" class="badge bg-[#fff3db] text-[#8f5b00]">Attention</span>
</div>
<p class="text-sm text-[#355947]">
{{
profileIsComplete
? 'Данные контрагента заполнены.'
? `Компания: ${companyNamePreview || 'данные сохранены'}`
: 'Пожалуйста, заполните карточку контрагента, чтобы получить максимум возможностей личного кабинета.'
}}
</p>
</NuxtLink>
<NuxtLink to="/profile/notifications" class="block rounded-3xl border border-[#d6ebde] bg-[#f7fffb] p-5 transition hover:shadow-md">
<p class="text-sm opacity-70">Уведомления</p>
<p class="mt-2 text-lg font-bold text-[#123824]">{{ connectedMessengerCount }}/2 каналов подключено</p>
<p class="mt-2 text-sm text-[#355947]">{{ notificationsSummary }}</p>
<NuxtLink to="/profile/notifications" class="block rounded-3xl bg-white p-5 transition hover:shadow-md">
<div class="mb-2 flex items-center justify-between gap-2">
<p class="text-lg font-bold text-[#123824]">Уведомления</p>
<span v-if="connectedMessengerCount < 2" class="badge bg-[#fff3db] text-[#8f5b00]">Attention</span>
</div>
<div class="mb-2 flex items-center justify-end gap-2">
<span
class="inline-flex h-8 w-8 items-center justify-center rounded-full text-xs font-bold"
:class="telegramConnected ? 'bg-[#def6ea] text-[#0d854a]' : 'bg-[#eceff3] text-[#6b7280]'"
>
TG
</span>
<span
class="inline-flex h-8 w-8 items-center justify-center rounded-full text-xs font-bold"
:class="maxConnected ? 'bg-[#def6ea] text-[#0d854a]' : 'bg-[#eceff3] text-[#6b7280]'"
>
MX
</span>
</div>
<p class="text-sm text-[#355947]">{{ notificationsSummary }}</p>
</NuxtLink>
<NuxtLink to="/profile/addresses" class="block rounded-3xl border border-[#d6ebde] bg-[#f7fffb] p-5 transition hover:shadow-md">
<p class="text-sm opacity-70">Адреса доставки</p>
<p class="mt-2 text-lg font-bold text-[#123824]">{{ deliveryAddresses.length }}</p>
<p class="mt-2 text-sm text-[#355947]">
<NuxtLink to="/profile/addresses" class="block rounded-3xl bg-white p-5 transition hover:shadow-md">
<div class="mb-2 flex items-start justify-between gap-2">
<p class="text-lg font-bold text-[#123824]">Адреса доставки</p>
<span v-if="!defaultDeliveryAddress" class="badge bg-[#fff3db] text-[#8f5b00]">Attention</span>
</div>
<p class="text-sm text-[#355947]">
{{
defaultDeliveryAddress
? `Основной: ${defaultDeliveryAddress.label || defaultDeliveryAddress.address}`
: 'Адреса пока не добавлены. Добавьте минимум один адрес доставки.'
: 'Добавьте первый адрес доставки, чтобы быстро оформлять заказы в корзине.'
}}
</p>
</NuxtLink>

View File

@@ -193,7 +193,7 @@ onBeforeUnmount(() => {
<fieldset class="fieldset mt-4">
<legend class="fieldset-legend">Название адреса (необязательно)</legend>
<input v-model="addressForm.label" type="text" class="input input-bordered w-full" placeholder="Склад МСК" >
<input v-model="addressForm.label" type="text" class="input w-full" placeholder="Склад МСК" >
</fieldset>
<div ref="addressDropdownRef" class="relative mt-2">
@@ -202,7 +202,7 @@ onBeforeUnmount(() => {
<input
v-model="addressSearch"
type="text"
class="input input-bordered w-full"
class="input w-full"
placeholder="Начните вводить адрес"
@input="scheduleAddressSuggest"
@focus="addressOpen = addressSuggestions.length > 0"
@@ -213,7 +213,7 @@ onBeforeUnmount(() => {
<div
v-if="addressOpen && addressSuggestions.length > 0"
class="absolute z-30 mt-2 max-h-72 w-full overflow-auto rounded-box border border-base-300 bg-base-100 p-2 shadow-xl"
class="absolute z-30 mt-2 max-h-72 w-full overflow-auto rounded-box bg-base-100 p-2"
>
<button
v-for="item in addressSuggestions"
@@ -240,15 +240,15 @@ onBeforeUnmount(() => {
<h2 class="text-xl font-bold text-[#123824]">Список адресов</h2>
<div class="mt-4 space-y-2">
<div v-if="deliveryAddressesQuery.loading.value" class="alert surface-card border-0">Загрузка адресов...</div>
<div v-else-if="deliveryAddresses.length === 0" class="alert surface-card border-0">
<div v-if="deliveryAddressesQuery.loading.value" class="alert surface-card">Загрузка адресов...</div>
<div v-else-if="deliveryAddresses.length === 0" class="alert surface-card">
Пока нет адресов доставки.
</div>
<article
v-for="address in deliveryAddresses"
:key="address.id"
class="rounded-2xl border border-[#d6ebde] bg-white/75 p-3"
class="rounded-2xl bg-[#f8fbf9] p-3 transition hover:shadow-md"
>
<div class="flex items-start justify-between gap-2">
<div>

View File

@@ -272,7 +272,7 @@ onBeforeUnmount(() => {
<input
v-model="companySearch"
type="text"
class="input input-bordered w-full"
class="input w-full"
placeholder="Введите название или ИНН"
@input="schedulePartySuggest"
@focus="partyOpen = partySuggestions.length > 0"
@@ -283,7 +283,7 @@ onBeforeUnmount(() => {
<div
v-if="partyOpen && partySuggestions.length > 0"
class="absolute z-30 mt-2 max-h-72 w-full overflow-auto rounded-box border border-base-300 bg-base-100 p-2 shadow-xl"
class="absolute z-30 mt-2 max-h-72 w-full overflow-auto rounded-box bg-base-100 p-2"
>
<button
v-for="item in partySuggestions"
@@ -302,34 +302,34 @@ onBeforeUnmount(() => {
<fieldset class="fieldset">
<legend class="fieldset-legend">Краткое наименование</legend>
<input v-model="counterpartyForm.companyName" type="text" class="input input-bordered w-full" >
<input v-model="counterpartyForm.companyName" type="text" class="input w-full" >
</fieldset>
<fieldset class="fieldset">
<legend class="fieldset-legend">Полное наименование</legend>
<input v-model="counterpartyForm.companyFullName" type="text" class="input input-bordered w-full" >
<input v-model="counterpartyForm.companyFullName" type="text" class="input w-full" >
</fieldset>
<div class="grid gap-3 sm:grid-cols-3">
<fieldset class="fieldset">
<legend class="fieldset-legend">ИНН</legend>
<input v-model="counterpartyForm.inn" type="text" class="input input-bordered w-full" >
<input v-model="counterpartyForm.inn" type="text" class="input w-full" >
</fieldset>
<fieldset class="fieldset">
<legend class="fieldset-legend">КПП</legend>
<input v-model="counterpartyForm.kpp" type="text" class="input input-bordered w-full" >
<input v-model="counterpartyForm.kpp" type="text" class="input w-full" >
</fieldset>
<fieldset class="fieldset">
<legend class="fieldset-legend">ОГРН</legend>
<input v-model="counterpartyForm.ogrn" type="text" class="input input-bordered w-full" >
<input v-model="counterpartyForm.ogrn" type="text" class="input w-full" >
</fieldset>
</div>
<fieldset class="fieldset">
<legend class="fieldset-legend">Юридический адрес</legend>
<textarea v-model="counterpartyForm.legalAddress" class="textarea textarea-bordered min-h-24 w-full" />
<textarea v-model="counterpartyForm.legalAddress" class="textarea min-h-24 w-full" />
</fieldset>
</section>
@@ -344,7 +344,7 @@ onBeforeUnmount(() => {
<input
v-model="bankSearch"
type="text"
class="input input-bordered w-full"
class="input w-full"
placeholder="Введите название банка"
@input="scheduleBankSuggest"
@focus="bankOpen = bankSuggestions.length > 0"
@@ -355,7 +355,7 @@ onBeforeUnmount(() => {
<div
v-if="bankOpen && bankSuggestions.length > 0"
class="absolute z-30 mt-2 max-h-72 w-full overflow-auto rounded-box border border-base-300 bg-base-100 p-2 shadow-xl"
class="absolute z-30 mt-2 max-h-72 w-full overflow-auto rounded-box bg-base-100 p-2"
>
<button
v-for="item in bankSuggestions"
@@ -374,24 +374,24 @@ onBeforeUnmount(() => {
<fieldset class="fieldset">
<legend class="fieldset-legend">Банк</legend>
<input v-model="counterpartyForm.bankName" type="text" class="input input-bordered w-full" >
<input v-model="counterpartyForm.bankName" type="text" class="input w-full" >
</fieldset>
<div class="grid gap-3 sm:grid-cols-2">
<fieldset class="fieldset">
<legend class="fieldset-legend">БИК</legend>
<input v-model="counterpartyForm.bik" type="text" class="input input-bordered w-full" >
<input v-model="counterpartyForm.bik" type="text" class="input w-full" >
</fieldset>
<fieldset class="fieldset">
<legend class="fieldset-legend">Корр. счет</legend>
<input v-model="counterpartyForm.correspondentAccount" type="text" class="input input-bordered w-full" >
<input v-model="counterpartyForm.correspondentAccount" type="text" class="input w-full" >
</fieldset>
</div>
<fieldset class="fieldset">
<legend class="fieldset-legend">Расчетный счет</legend>
<input v-model="counterpartyForm.checkingAccount" type="text" class="input input-bordered w-full" >
<input v-model="counterpartyForm.checkingAccount" type="text" class="input w-full" >
</fieldset>
</section>
@@ -402,19 +402,19 @@ onBeforeUnmount(() => {
<fieldset class="fieldset">
<legend class="fieldset-legend">ФИО подписанта</legend>
<input v-model="counterpartyForm.signerFullName" type="text" class="input input-bordered w-full" placeholder="Иванов Иван Иванович" >
<input v-model="counterpartyForm.signerFullName" type="text" class="input w-full" placeholder="Иванов Иван Иванович" >
</fieldset>
<fieldset class="fieldset">
<legend class="fieldset-legend">Должность</legend>
<input v-model="counterpartyForm.signerPosition" type="text" class="input input-bordered w-full" placeholder="Генеральный директор" >
<input v-model="counterpartyForm.signerPosition" type="text" class="input w-full" placeholder="Генеральный директор" >
</fieldset>
<fieldset class="fieldset">
<legend class="fieldset-legend">Основание полномочий</legend>
<textarea
v-model="counterpartyForm.signerBasis"
class="textarea textarea-bordered min-h-24 w-full"
class="textarea min-h-24 w-full"
placeholder="Действует на основании Устава"
/>
</fieldset>

View File

@@ -52,7 +52,7 @@ const maxConnectUrl = computed(() => buildBotConnectUrl(config.public.maxBotUrl
</p>
<div class="mt-4 space-y-3">
<div class="rounded-2xl border border-[#d6ebde] bg-white/75 p-4">
<div class="rounded-2xl bg-[#f8fbf9] p-4 transition hover:shadow-md">
<p class="font-semibold">Telegram</p>
<p class="text-sm opacity-80">
{{ telegramConnection ? `Подключен: ${telegramConnection.channelId}` : 'Не подключен' }}
@@ -68,7 +68,7 @@ const maxConnectUrl = computed(() => buildBotConnectUrl(config.public.maxBotUrl
</a>
</div>
<div class="rounded-2xl border border-[#d6ebde] bg-white/75 p-4">
<div class="rounded-2xl bg-[#f8fbf9] p-4 transition hover:shadow-md">
<p class="font-semibold">Max</p>
<p class="text-sm opacity-80">
{{ maxConnection ? `Подключен: ${maxConnection.channelId}` : 'Не подключен' }}