2026-09-02 21:29:00 +03:30
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { computed, onMounted, ref, watch } from 'vue';
|
|
|
|
|
import { RouterLink, useRoute, useRouter } from 'vue-router';
|
|
|
|
|
import { api } from '@/lib/api';
|
|
|
|
|
import {
|
|
|
|
|
calendarDaysBetween,
|
|
|
|
|
formatClockFa,
|
|
|
|
|
formatJalaliDay,
|
|
|
|
|
} from '@/lib/jalali';
|
|
|
|
|
import UiIcon from '@/components/UiIcon.vue';
|
|
|
|
|
import UserAvatar from '@/components/UserAvatar.vue';
|
|
|
|
|
import ActivityCommentSheet from '@/components/activities/ActivityCommentSheet.vue';
|
|
|
|
|
import ActivityPostponeSheet from '@/components/activities/ActivityPostponeSheet.vue';
|
|
|
|
|
import type { ActivityDto, ActivityPriority, ActivityType } from '@mento/shared';
|
|
|
|
|
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
const id = computed(() => (typeof route.params.id === 'string' ? route.params.id : ''));
|
|
|
|
|
|
|
|
|
|
const loading = ref(true);
|
|
|
|
|
const saving = ref(false);
|
|
|
|
|
const error = ref('');
|
|
|
|
|
const activity = ref<ActivityDto | null>(null);
|
|
|
|
|
const moreOpen = ref(false);
|
|
|
|
|
const commentOpen = ref(false);
|
|
|
|
|
const postponeOpen = ref(false);
|
|
|
|
|
const noteOpen = ref(true);
|
|
|
|
|
|
|
|
|
|
const typeLabel: Record<ActivityType, string> = {
|
|
|
|
|
call: 'تماس',
|
|
|
|
|
meeting: 'جلسه',
|
|
|
|
|
task: 'وظیفه',
|
|
|
|
|
note: 'پیام',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const typeIcon: Record<ActivityType, 'phone' | 'users' | 'check' | 'chat'> = {
|
|
|
|
|
call: 'phone',
|
|
|
|
|
meeting: 'users',
|
|
|
|
|
task: 'check',
|
|
|
|
|
note: 'chat',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const priorityLabel: Record<ActivityPriority, string> = {
|
|
|
|
|
very_low: 'خیلی کم',
|
|
|
|
|
low: 'کم',
|
|
|
|
|
medium: 'متوسط',
|
|
|
|
|
high: 'زیاد',
|
|
|
|
|
very_high: 'خیلی زیاد',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const subtitle = computed(() => {
|
|
|
|
|
const a = activity.value;
|
|
|
|
|
if (!a) return '';
|
|
|
|
|
return a.deal?.title || a.company?.name || a.person?.fullName || '';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const dueLabel = computed(() => {
|
|
|
|
|
const due = activity.value?.dueAt;
|
|
|
|
|
if (!due) return 'بدون موعد';
|
|
|
|
|
const d = new Date(due);
|
|
|
|
|
const days = calendarDaysBetween(d, new Date());
|
|
|
|
|
const clock = formatClockFa(d);
|
|
|
|
|
if (days === 0) return `امروز - ${clock}`;
|
|
|
|
|
if (days === 1) return `دیروز - ${clock}`;
|
|
|
|
|
if (days === -1) return `فردا - ${clock}`;
|
|
|
|
|
return `${formatJalaliDay(d)} - ${clock}`;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const createdLabel = computed(() => {
|
|
|
|
|
const raw = activity.value?.createdAt;
|
|
|
|
|
if (!raw) return '—';
|
|
|
|
|
const d = new Date(raw);
|
|
|
|
|
return `${formatJalaliDay(d)} - ${formatClockFa(d)}`;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const isDone = computed(() => activity.value?.status === 'done');
|
|
|
|
|
const statusText = computed(() => {
|
|
|
|
|
if (!activity.value) return '—';
|
|
|
|
|
if (activity.value.status === 'done') return 'انجام شد';
|
|
|
|
|
if (activity.value.status === 'canceled') return 'لغو شده';
|
|
|
|
|
return 'انجام نشده';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
async function load() {
|
|
|
|
|
if (!id.value) return;
|
|
|
|
|
loading.value = true;
|
|
|
|
|
error.value = '';
|
|
|
|
|
moreOpen.value = false;
|
|
|
|
|
try {
|
|
|
|
|
const { data } = await api.get<ActivityDto>(`/activities/${id.value}`);
|
|
|
|
|
activity.value = data;
|
|
|
|
|
} catch {
|
|
|
|
|
error.value = 'بارگذاری جزئیات فعالیت ناموفق بود.';
|
|
|
|
|
activity.value = null;
|
|
|
|
|
} finally {
|
|
|
|
|
loading.value = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function complete() {
|
|
|
|
|
if (!id.value || isDone.value) return;
|
|
|
|
|
saving.value = true;
|
|
|
|
|
error.value = '';
|
|
|
|
|
try {
|
|
|
|
|
await api.patch(`/activities/${id.value}/complete`);
|
|
|
|
|
await router.push({ name: 'activities' });
|
|
|
|
|
} catch {
|
|
|
|
|
error.value = 'ثبت انجامشدن ناموفق بود.';
|
|
|
|
|
} finally {
|
|
|
|
|
saving.value = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function postponeTo(iso: string) {
|
|
|
|
|
if (!id.value || !activity.value || isDone.value) return;
|
|
|
|
|
saving.value = true;
|
|
|
|
|
error.value = '';
|
|
|
|
|
try {
|
|
|
|
|
await api.patch(`/activities/${id.value}`, { dueAt: iso });
|
|
|
|
|
postponeOpen.value = false;
|
|
|
|
|
await load();
|
|
|
|
|
} catch {
|
|
|
|
|
error.value = 'تعویق فعالیت ناموفق بود.';
|
|
|
|
|
} finally {
|
|
|
|
|
saving.value = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function submitComment(text: string) {
|
|
|
|
|
const body = text.trim();
|
|
|
|
|
if (!id.value || !activity.value || !body) return;
|
|
|
|
|
saving.value = true;
|
|
|
|
|
error.value = '';
|
|
|
|
|
try {
|
|
|
|
|
const prev = activity.value.description?.trim();
|
|
|
|
|
const next = prev ? `${prev}\n${body}` : body;
|
|
|
|
|
await api.patch(`/activities/${id.value}`, { description: next });
|
|
|
|
|
commentOpen.value = false;
|
|
|
|
|
await load();
|
|
|
|
|
} catch {
|
|
|
|
|
error.value = 'ثبت نظر ناموفق بود.';
|
|
|
|
|
} finally {
|
|
|
|
|
saving.value = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function remove() {
|
|
|
|
|
moreOpen.value = false;
|
|
|
|
|
if (!id.value || !confirm('این فعالیت حذف شود؟')) return;
|
|
|
|
|
try {
|
|
|
|
|
await api.delete(`/activities/${id.value}`);
|
|
|
|
|
await router.push({ name: 'activities' });
|
|
|
|
|
} catch {
|
|
|
|
|
error.value = 'حذف ناموفق بود.';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
watch(id, () => {
|
|
|
|
|
commentOpen.value = false;
|
|
|
|
|
postponeOpen.value = false;
|
|
|
|
|
void load();
|
|
|
|
|
});
|
|
|
|
|
onMounted(load);
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<section class="page" @click="moreOpen = false">
|
|
|
|
|
<header class="nav">
|
|
|
|
|
<RouterLink class="icon-btn back" :to="{ name: 'activities' }" aria-label="بازگشت">
|
|
|
|
|
<UiIcon name="chevron" :size="18" />
|
|
|
|
|
</RouterLink>
|
|
|
|
|
<span class="brand">mento</span>
|
|
|
|
|
<div class="more" @click.stop>
|
|
|
|
|
<button class="icon-btn" type="button" aria-label="منوی بیشتر" @click="moreOpen = !moreOpen">
|
|
|
|
|
<UiIcon name="dots-v" :size="18" />
|
|
|
|
|
</button>
|
|
|
|
|
<div v-if="moreOpen && activity" class="menu">
|
|
|
|
|
<RouterLink :to="{ name: 'activity-edit', params: { id } }">ویرایش</RouterLink>
|
|
|
|
|
<button type="button" class="danger" @click="remove">حذف</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<h1>جزئیات فعالیت</h1>
|
|
|
|
|
<p v-if="loading" class="muted">در حال بارگذاری…</p>
|
|
|
|
|
<p v-else-if="error && !activity" class="error">{{ error }}</p>
|
|
|
|
|
|
|
|
|
|
<template v-else-if="activity">
|
|
|
|
|
<article class="card">
|
|
|
|
|
<header class="hero">
|
|
|
|
|
<div>
|
|
|
|
|
<h2>
|
|
|
|
|
{{ activity.title }}
|
|
|
|
|
<UiIcon name="star" :size="16" class="star" />
|
|
|
|
|
</h2>
|
|
|
|
|
<p v-if="subtitle" class="sub">
|
|
|
|
|
<UiIcon name="building" :size="14" />
|
|
|
|
|
{{ subtitle }}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
<span class="type-ico" :class="activity.type">
|
|
|
|
|
<UiIcon :name="typeIcon[activity.type]" :size="22" />
|
|
|
|
|
</span>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<dl>
|
|
|
|
|
<div>
|
|
|
|
|
<dt>
|
|
|
|
|
<UiIcon :name="typeIcon[activity.type]" :size="15" />
|
|
|
|
|
نوع فعالیت
|
|
|
|
|
</dt>
|
|
|
|
|
<dd>{{ typeLabel[activity.type] }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<dt>
|
|
|
|
|
<UiIcon name="calendar" :size="15" />
|
|
|
|
|
تاریخ و زمان
|
|
|
|
|
</dt>
|
|
|
|
|
<dd>{{ dueLabel }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<dt>
|
|
|
|
|
<UiIcon name="user" :size="15" />
|
|
|
|
|
مسئول
|
|
|
|
|
</dt>
|
|
|
|
|
<dd class="person">
|
|
|
|
|
<UserAvatar v-if="activity.assignee" :name="activity.assignee.fullName" :size="28" />
|
|
|
|
|
{{ activity.assignee?.fullName || '—' }}
|
|
|
|
|
</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<dt>
|
|
|
|
|
<UiIcon name="flag" :size="15" class="flag" :class="activity.priority || 'medium'" />
|
|
|
|
|
اولویت
|
|
|
|
|
</dt>
|
|
|
|
|
<dd class="priority" :class="activity.priority || 'medium'">
|
|
|
|
|
{{ priorityLabel[activity.priority || 'medium'] }}
|
|
|
|
|
</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<dt>وضعیت</dt>
|
|
|
|
|
<dd>
|
|
|
|
|
<span class="status" :class="{ done: isDone }">{{ statusText }}</span>
|
|
|
|
|
</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<dt>
|
|
|
|
|
<UiIcon name="user" :size="15" />
|
|
|
|
|
ایجاد شده توسط
|
|
|
|
|
</dt>
|
|
|
|
|
<dd class="person">
|
|
|
|
|
<UserAvatar v-if="activity.createdBy" :name="activity.createdBy.fullName" :size="28" />
|
|
|
|
|
{{ activity.createdBy?.fullName || '—' }}
|
|
|
|
|
</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<dt>
|
|
|
|
|
<UiIcon name="calendar" :size="15" />
|
|
|
|
|
تاریخ ایجاد
|
|
|
|
|
</dt>
|
|
|
|
|
<dd>{{ createdLabel }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
</dl>
|
|
|
|
|
</article>
|
|
|
|
|
|
|
|
|
|
<article class="card note">
|
|
|
|
|
<button class="note-head" type="button" @click="noteOpen = !noteOpen">
|
|
|
|
|
<strong>
|
|
|
|
|
<UiIcon name="document" :size="16" />
|
|
|
|
|
یادداشت
|
|
|
|
|
</strong>
|
|
|
|
|
<UiIcon name="chevron" :size="16" :class="{ open: noteOpen }" />
|
|
|
|
|
</button>
|
|
|
|
|
<p v-show="noteOpen" :class="{ empty: !activity.description?.trim() }">
|
|
|
|
|
{{ activity.description?.trim() || 'یادداشتی ثبت نشده.' }}
|
|
|
|
|
</p>
|
|
|
|
|
</article>
|
|
|
|
|
|
|
|
|
|
<p v-if="error" class="error">{{ error }}</p>
|
|
|
|
|
|
|
|
|
|
<ActivityCommentSheet
|
|
|
|
|
v-if="commentOpen"
|
|
|
|
|
:activity="activity"
|
|
|
|
|
:saving="saving"
|
|
|
|
|
@close="commentOpen = false"
|
|
|
|
|
@submit="submitComment"
|
|
|
|
|
/>
|
|
|
|
|
<ActivityPostponeSheet
|
|
|
|
|
v-if="postponeOpen"
|
|
|
|
|
:due-at="activity.dueAt"
|
|
|
|
|
:saving="saving"
|
|
|
|
|
@close="postponeOpen = false"
|
|
|
|
|
@submit="postponeTo"
|
|
|
|
|
/>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<footer v-if="activity && !commentOpen && !postponeOpen" class="dock">
|
|
|
|
|
<button class="act primary" type="button" :disabled="saving || isDone" @click="complete">
|
|
|
|
|
<UiIcon name="check" :size="16" />
|
|
|
|
|
انجام شد
|
|
|
|
|
</button>
|
|
|
|
|
<button class="act ghost" type="button" :disabled="saving || isDone" @click="postponeOpen = true">
|
|
|
|
|
<UiIcon name="refresh" :size="16" />
|
|
|
|
|
تعویق
|
|
|
|
|
</button>
|
|
|
|
|
<button class="act ghost" type="button" :disabled="saving" @click="commentOpen = true">
|
|
|
|
|
<UiIcon name="chat" :size="16" />
|
|
|
|
|
ثبت نظر
|
|
|
|
|
</button>
|
|
|
|
|
</footer>
|
|
|
|
|
</section>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.page {
|
|
|
|
|
width: 100%;
|
2026-09-12 01:33:07 +03:30
|
|
|
max-width: 100%;
|
2026-09-02 21:29:00 +03:30
|
|
|
min-width: 0;
|
2026-09-12 01:33:07 +03:30
|
|
|
margin: 0;
|
2026-09-02 21:29:00 +03:30
|
|
|
display: grid;
|
|
|
|
|
gap: 0.9rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.nav {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
position: relative;
|
|
|
|
|
z-index: 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.brand {
|
2026-09-12 01:33:07 +03:30
|
|
|
font-weight: 600;
|
2026-09-02 21:29:00 +03:30
|
|
|
color: #0f766e;
|
|
|
|
|
letter-spacing: -0.04em;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.icon-btn {
|
|
|
|
|
width: 38px;
|
|
|
|
|
height: 38px;
|
|
|
|
|
border: 0;
|
|
|
|
|
background: #fff;
|
2026-09-12 01:33:07 +03:30
|
|
|
border-radius: var(--radius);
|
2026-09-02 21:29:00 +03:30
|
|
|
display: grid;
|
|
|
|
|
place-items: center;
|
|
|
|
|
color: #334155;
|
|
|
|
|
box-shadow: 0 4px 12px rgba(15, 23, 42, 0.05);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.back :deep(.ico) {
|
|
|
|
|
transform: scaleX(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.more {
|
|
|
|
|
position: relative;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.menu {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: calc(100% + 6px);
|
|
|
|
|
inset-inline-end: 0;
|
|
|
|
|
min-width: 10rem;
|
|
|
|
|
background: #fff;
|
2026-09-12 01:33:07 +03:30
|
|
|
border-radius: var(--radius);
|
2026-09-02 21:29:00 +03:30
|
|
|
box-shadow: 0 16px 40px rgba(15, 23, 42, 0.14);
|
|
|
|
|
padding: 0.35rem;
|
|
|
|
|
display: grid;
|
|
|
|
|
z-index: 6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.menu a,
|
|
|
|
|
.menu button {
|
|
|
|
|
display: block;
|
|
|
|
|
width: 100%;
|
|
|
|
|
text-align: start;
|
|
|
|
|
border: 0;
|
|
|
|
|
background: none;
|
|
|
|
|
padding: 0.62rem 0.75rem;
|
2026-09-12 01:33:07 +03:30
|
|
|
border-radius: var(--radius);
|
2026-09-02 21:29:00 +03:30
|
|
|
font: inherit;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
color: #0f172a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.menu .danger {
|
|
|
|
|
color: #b91c1c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
h1 {
|
|
|
|
|
margin: 0.1rem 0 0;
|
|
|
|
|
font-size: 1.35rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.muted,
|
|
|
|
|
.error {
|
|
|
|
|
margin: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.muted {
|
|
|
|
|
color: #64748b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.error {
|
|
|
|
|
color: #b91c1c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.card {
|
|
|
|
|
background: #fff;
|
2026-09-12 01:33:07 +03:30
|
|
|
border-radius: var(--radius);
|
2026-09-02 21:29:00 +03:30
|
|
|
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.05);
|
|
|
|
|
padding: 1rem 1.05rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hero {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
gap: 0.8rem;
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
padding-bottom: 0.85rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hero h2 {
|
|
|
|
|
margin: 0;
|
|
|
|
|
font-size: 1.05rem;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
gap: 0.35rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.star {
|
|
|
|
|
color: #cbd5e1;
|
|
|
|
|
margin-top: 0.15rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.sub {
|
|
|
|
|
margin: 0.4rem 0 0;
|
|
|
|
|
color: #64748b;
|
|
|
|
|
font-size: 0.84rem;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 0.3rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.type-ico {
|
|
|
|
|
width: 48px;
|
|
|
|
|
height: 48px;
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
display: grid;
|
|
|
|
|
place-items: center;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.type-ico.call {
|
|
|
|
|
background: #ecfdf5;
|
|
|
|
|
color: #0f766e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.type-ico.meeting {
|
|
|
|
|
background: #f5f3ff;
|
|
|
|
|
color: #6d28d9;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.type-ico.task {
|
|
|
|
|
background: #fff7ed;
|
|
|
|
|
color: #c2410c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.type-ico.note {
|
|
|
|
|
background: #eff6ff;
|
|
|
|
|
color: #2563eb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dl {
|
|
|
|
|
margin: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dl > div {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
gap: 0.8rem;
|
|
|
|
|
align-items: center;
|
|
|
|
|
padding: 0.78rem 0;
|
|
|
|
|
border-top: 1px solid #f1f5f9;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dt,
|
|
|
|
|
dd {
|
|
|
|
|
margin: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dt {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 0.4rem;
|
|
|
|
|
color: #64748b;
|
|
|
|
|
font-size: 0.86rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dd {
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
text-align: start;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.person {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 0.45rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.flag.low,
|
|
|
|
|
.priority.low {
|
|
|
|
|
color: #64748b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.flag.medium,
|
|
|
|
|
.priority.medium {
|
|
|
|
|
color: #ea580c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.flag.high,
|
|
|
|
|
.priority.high {
|
|
|
|
|
color: #dc2626;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.status {
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
padding: 0.22rem 0.65rem;
|
|
|
|
|
background: #ecfdf5;
|
|
|
|
|
color: #0f766e;
|
|
|
|
|
font-size: 0.8rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.status.done {
|
|
|
|
|
background: #dcfce7;
|
|
|
|
|
color: #166534;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.note-head {
|
|
|
|
|
width: 100%;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
border: 0;
|
|
|
|
|
background: none;
|
|
|
|
|
padding: 0;
|
|
|
|
|
font: inherit;
|
|
|
|
|
color: #0f766e;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.note-head :deep(.ico:last-child) {
|
|
|
|
|
transform: rotate(90deg);
|
|
|
|
|
color: #94a3b8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.note-head :deep(.ico.open) {
|
|
|
|
|
transform: rotate(-90deg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.note p {
|
|
|
|
|
margin: 0.75rem 0 0;
|
|
|
|
|
color: #334155;
|
|
|
|
|
line-height: 1.9;
|
|
|
|
|
font-size: 0.9rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.note p.empty {
|
|
|
|
|
color: #94a3b8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dock {
|
|
|
|
|
position: fixed;
|
|
|
|
|
inset-inline: 0.85rem;
|
|
|
|
|
bottom: calc(0.55rem + env(safe-area-inset-bottom));
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: 1.15fr 1fr 1fr;
|
|
|
|
|
gap: 0.5rem;
|
|
|
|
|
z-index: 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.act {
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
gap: 0.3rem;
|
2026-09-10 23:45:11 +03:30
|
|
|
min-height: var(--control-h);
|
|
|
|
|
height: var(--control-h);
|
|
|
|
|
border-radius: var(--radius);
|
2026-09-02 21:29:00 +03:30
|
|
|
border: 1px solid #99f6e4;
|
|
|
|
|
background: #fff;
|
|
|
|
|
color: #0f766e;
|
|
|
|
|
font: inherit;
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.act.primary {
|
|
|
|
|
background: #14b8a6;
|
|
|
|
|
border-color: #14b8a6;
|
|
|
|
|
color: #fff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.act:disabled {
|
|
|
|
|
opacity: 0.45;
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (min-width: 900px) {
|
|
|
|
|
.dock {
|
|
|
|
|
position: sticky;
|
|
|
|
|
inset-inline: auto;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|