fix: keep list menus on screen and clip long activity subtitles

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-17 13:26:11 +03:30
co-authored by Cursor
parent 2c7c943802
commit 177e5cc31b
5 changed files with 158 additions and 101 deletions
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed } from 'vue';
import { computed, onMounted, onUnmounted, ref } from 'vue';
import TableColumnsMenu from '@/components/TableColumnsMenu.vue';
import UiIcon from '@/components/UiIcon.vue';
import type { PipelineDeal, PipelineStage, PipelineUiCopy } from '@/lib/pipeline-board';
@@ -26,6 +26,11 @@ const emit = defineEmits<{
bulkDelete: [];
}>();
const listRoot = ref<HTMLElement | null>(null);
/** فقط یکی از جدول/کارت در DOM باشد تا منوی انتخاب گم نشود */
const useCards = ref(false);
let resizeObs: ResizeObserver | null = null;
const rows = computed(() =>
props.stages.flatMap((stage) =>
stage.deals.map((deal) => ({
@@ -42,16 +47,32 @@ function money(deal: PipelineDeal) {
const hideAmount = computed(() => Boolean(props.copy.hideAmount));
const tableKey = computed(() => (hideAmount.value ? 'pipeline.leads' : 'pipeline.deals'));
onMounted(() => {
const el = listRoot.value;
if (!el || typeof ResizeObserver === 'undefined') return;
resizeObs = new ResizeObserver((entries) => {
const width = entries[0]?.contentRect.width ?? el.clientWidth;
useCards.value = width <= 720;
});
resizeObs.observe(el);
useCards.value = el.clientWidth <= 720;
});
onUnmounted(() => {
resizeObs?.disconnect();
resizeObs = null;
});
</script>
<template>
<div class="list" dir="rtl">
<div ref="listRoot" class="list" dir="rtl">
<p v-if="!rows.length" class="empty">{{ copy.empty }}</p>
<div v-if="rows.length" class="tc-row">
<div v-if="rows.length && !useCards" class="tc-row">
<TableColumnsMenu :table-key="tableKey" align="end" />
</div>
<div v-if="rows.length" class="table-wrap">
<div v-if="rows.length && !useCards" class="table-wrap">
<table v-table-cols="tableKey" class="data-table">
<thead>
<tr>
@@ -60,7 +81,7 @@ const tableKey = computed(() => (hideAmount.value ? 'pipeline.leads' : 'pipeline
<th>مرحله</th>
<th v-if="!hideAmount">مبلغ</th>
<th>تاریخ</th>
<th></th>
<th class="menu-col">عملیات</th>
</tr>
</thead>
<tbody>
@@ -155,7 +176,7 @@ const tableKey = computed(() => (hideAmount.value ? 'pipeline.leads' : 'pipeline
</table>
</div>
<div v-if="rows.length" class="cards">
<div v-if="rows.length && useCards" class="cards">
<article
v-for="row in rows"
:key="row.deal.id"
@@ -412,16 +433,23 @@ const tableKey = computed(() => (hideAmount.value ? 'pipeline.leads' : 'pipeline
white-space: nowrap;
}
.menu-col,
.menu-cell {
width: 2.5rem;
width: 3.2rem;
min-width: 3.2rem;
text-align: center;
}
.menu {
border: 0;
background: transparent;
color: var(--muted);
padding: 0.2rem;
width: 2rem;
height: 2rem;
padding: 0;
border-radius: var(--radius);
display: inline-grid;
place-items: center;
cursor: pointer;
}
@@ -442,7 +470,7 @@ const tableKey = computed(() => (hideAmount.value ? 'pipeline.leads' : 'pipeline
}
.cards {
display: none;
display: grid;
gap: 0.7rem;
}
@@ -479,13 +507,4 @@ const tableKey = computed(() => (hideAmount.value ? 'pipeline.leads' : 'pipeline
gap: 0.5rem;
}
@container pipeline (max-width: 720px) {
.table-wrap {
display: none;
}
.cards {
display: grid;
}
}
</style>