Make note cards equal squares and open the editor as a centered modal.
Unify desktop and mobile create/edit into one modal dialog with a consistent grid layout. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+274
-319
@@ -51,7 +51,6 @@ const blobCache = ref<Record<string, string>>({});
|
||||
const audioDurations = ref<Record<string, string>>({});
|
||||
|
||||
const editorOpen = ref(false);
|
||||
const mobileEditor = ref(false);
|
||||
const moreSheetOpen = ref(false);
|
||||
const showChecklistEditor = ref(false);
|
||||
const editingId = ref<string | null>(null);
|
||||
@@ -397,7 +396,6 @@ function openEditor(mode: OpenMode = 'default', note?: NoteDto) {
|
||||
}
|
||||
}
|
||||
|
||||
mobileEditor.value = isMobile.value;
|
||||
editorOpen.value = true;
|
||||
moreSheetOpen.value = false;
|
||||
|
||||
@@ -411,7 +409,6 @@ function openEditor(mode: OpenMode = 'default', note?: NoteDto) {
|
||||
|
||||
function closeEditor() {
|
||||
editorOpen.value = false;
|
||||
mobileEditor.value = false;
|
||||
moreSheetOpen.value = false;
|
||||
resetDraft();
|
||||
}
|
||||
@@ -836,7 +833,7 @@ onBeforeUnmount(() => {
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="note-card add-card desktop-only"
|
||||
class="note-card add-card"
|
||||
@click="openEditor()"
|
||||
>
|
||||
<UiIcon name="plus" :size="22" />
|
||||
@@ -880,12 +877,9 @@ onBeforeUnmount(() => {
|
||||
@change="onFilesSelected($event, 'audio')"
|
||||
/>
|
||||
|
||||
<!-- Desktop slide-over (RTL: start = left) -->
|
||||
<!-- Unified create/edit modal -->
|
||||
<Teleport to="body">
|
||||
<div
|
||||
v-if="editorOpen && !mobileEditor"
|
||||
class="panel-root desktop-panel"
|
||||
>
|
||||
<div v-if="editorOpen" class="panel-root">
|
||||
<div class="panel-backdrop" @click="closeEditor" />
|
||||
<aside
|
||||
class="editor-panel"
|
||||
@@ -896,9 +890,19 @@ onBeforeUnmount(() => {
|
||||
>
|
||||
<header class="panel-head">
|
||||
<h2>{{ editorTitle }}</h2>
|
||||
<button type="button" class="icon-btn" @click="closeEditor">
|
||||
<UiIcon name="x" :size="20" />
|
||||
</button>
|
||||
<div class="panel-head-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="btn-save mobile-only-flex"
|
||||
:disabled="saving"
|
||||
@click="saveNote"
|
||||
>
|
||||
{{ saving ? '…' : 'ذخیره' }}
|
||||
</button>
|
||||
<button type="button" class="icon-btn" @click="closeEditor">
|
||||
<UiIcon name="x" :size="20" />
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="panel-scroll">
|
||||
@@ -923,21 +927,14 @@ onBeforeUnmount(() => {
|
||||
:key="sw.value"
|
||||
type="button"
|
||||
class="swatch"
|
||||
:class="[
|
||||
`tone-${sw.value}`,
|
||||
{ selected: draftColor === sw.value },
|
||||
]"
|
||||
:class="[`tone-${sw.value}`, { selected: draftColor === sw.value }]"
|
||||
:style="{ backgroundColor: NOTE_COLOR_HEX[sw.value] }"
|
||||
:title="sw.label"
|
||||
:aria-label="sw.label"
|
||||
:aria-selected="draftColor === sw.value"
|
||||
@click="draftColor = sw.value"
|
||||
>
|
||||
<UiIcon
|
||||
v-if="draftColor === sw.value"
|
||||
name="check-plain"
|
||||
:size="14"
|
||||
/>
|
||||
<UiIcon v-if="draftColor === sw.value" name="check-plain" :size="14" />
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
@@ -951,7 +948,7 @@ onBeforeUnmount(() => {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="media-row">
|
||||
<div class="media-row desktop-only-flex">
|
||||
<button type="button" class="media-btn" @click="imageInput?.click()">
|
||||
<UiIcon name="layers" :size="18" /> تصویر
|
||||
</button>
|
||||
@@ -1018,66 +1015,67 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class="field">
|
||||
<span>نوع یادداشت</span>
|
||||
<select v-model="draftType">
|
||||
<option
|
||||
v-for="opt in noteTypeOptions"
|
||||
:key="opt.value"
|
||||
:value="opt.value"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<div class="field-row">
|
||||
<div class="desktop-fields">
|
||||
<label class="field">
|
||||
<span>مرتبط با — مشتری</span>
|
||||
<select v-model="draftPersonId">
|
||||
<option value="">—</option>
|
||||
<option v-for="p in people" :key="p.id" :value="p.id">
|
||||
{{ p.fullName }}
|
||||
<span>نوع یادداشت</span>
|
||||
<select v-model="draftType">
|
||||
<option
|
||||
v-for="opt in noteTypeOptions"
|
||||
:key="opt.value"
|
||||
:value="opt.value"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<div class="field-row">
|
||||
<label class="field">
|
||||
<span>مرتبط با — مشتری</span>
|
||||
<select v-model="draftPersonId">
|
||||
<option value="">—</option>
|
||||
<option v-for="p in people" :key="p.id" :value="p.id">
|
||||
{{ p.fullName }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>معامله</span>
|
||||
<select v-model="draftDealId">
|
||||
<option value="">—</option>
|
||||
<option v-for="d in deals" :key="d.id" :value="d.id">
|
||||
{{ d.title }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<label class="field">
|
||||
<span>معامله</span>
|
||||
<select v-model="draftDealId">
|
||||
<option value="">—</option>
|
||||
<option v-for="d in deals" :key="d.id" :value="d.id">
|
||||
{{ d.title }}
|
||||
</option>
|
||||
</select>
|
||||
<span>یادآوری</span>
|
||||
<JalaliDateInput v-model="draftReminder" mode="datetime" icon="bell" />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>برچسبها</span>
|
||||
<input v-model="draftTags" type="text" placeholder="مثلاً قیمت جلسه" />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>موقعیت</span>
|
||||
<input v-model="draftLocation" type="text" placeholder="اختیاری" />
|
||||
</label>
|
||||
<label class="ai-toggle">
|
||||
<input v-model="draftAnalyze" type="checkbox" />
|
||||
<div>
|
||||
<strong>تحلیل با هوش مصنوعی</strong>
|
||||
<p>پس از ذخیره، پیشنهاد کار بعدی و حافظه مشتری استخراج میشود.</p>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<label class="field">
|
||||
<span>یادآوری</span>
|
||||
<JalaliDateInput v-model="draftReminder" mode="datetime" icon="bell" />
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
<span>برچسبها</span>
|
||||
<input
|
||||
v-model="draftTags"
|
||||
type="text"
|
||||
placeholder="مثلاً قیمت جلسه"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
<span>موقعیت</span>
|
||||
<input v-model="draftLocation" type="text" placeholder="اختیاری" />
|
||||
</label>
|
||||
|
||||
<label class="ai-toggle">
|
||||
<input v-model="draftAnalyze" type="checkbox" />
|
||||
<div>
|
||||
<strong>تحلیل با هوش مصنوعی</strong>
|
||||
<p>پس از ذخیره، پیشنهاد کار بعدی و حافظه مشتری استخراج میشود.</p>
|
||||
</div>
|
||||
</label>
|
||||
<div class="chip-summary mobile-only-flex">
|
||||
<span v-for="(f, i) in draftFiles" :key="`mf-${i}`" class="tag-chip">{{ f.name }}</span>
|
||||
<span v-for="t in parseTags(draftTags)" :key="t" class="tag-chip">#{{ t }}</span>
|
||||
<span v-if="draftPersonId" class="tag-chip">{{ personName(draftPersonId) }}</span>
|
||||
<span v-if="draftDealId" class="tag-chip">معامله</span>
|
||||
<span v-if="draftLocation" class="tag-chip">{{ draftLocation }}</span>
|
||||
</div>
|
||||
|
||||
<NoteAiSuggestionPanel
|
||||
v-if="editingId"
|
||||
@@ -1088,7 +1086,7 @@ onBeforeUnmount(() => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<footer class="panel-foot">
|
||||
<footer class="panel-foot desktop-only-flex">
|
||||
<button
|
||||
type="button"
|
||||
class="btn-primary"
|
||||
@@ -1099,212 +1097,108 @@ onBeforeUnmount(() => {
|
||||
</button>
|
||||
<button type="button" class="btn-ghost" @click="closeEditor">لغو</button>
|
||||
</footer>
|
||||
</aside>
|
||||
</div>
|
||||
</Teleport>
|
||||
|
||||
<!-- Mobile full-screen editor -->
|
||||
<Teleport to="body">
|
||||
<div
|
||||
v-if="editorOpen && mobileEditor"
|
||||
class="mobile-editor"
|
||||
:style="{ '--canvas': draftColorCss, background: draftColorCss }"
|
||||
>
|
||||
<header class="mob-head">
|
||||
<button type="button" class="icon-btn" @click="closeEditor">
|
||||
<UiIcon name="x" :size="22" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-save"
|
||||
:disabled="saving"
|
||||
@click="saveNote"
|
||||
>
|
||||
{{ saving ? '…' : 'ذخیره' }}
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<div class="mob-canvas">
|
||||
<input
|
||||
v-model="draftTitle"
|
||||
class="title-input"
|
||||
type="text"
|
||||
placeholder="عنوان (اختیاری)"
|
||||
/>
|
||||
<textarea
|
||||
ref="bodyTextarea"
|
||||
v-model="draftBody"
|
||||
class="body-canvas"
|
||||
placeholder="یادداشت خود را بنویسید…"
|
||||
/>
|
||||
|
||||
<div class="palette-row">
|
||||
<div class="swatches" role="listbox" aria-label="رنگ یادداشت">
|
||||
<button
|
||||
v-for="sw in colorSwatches"
|
||||
:key="`m-${sw.value}`"
|
||||
type="button"
|
||||
class="swatch"
|
||||
:class="[`tone-${sw.value}`, { selected: draftColor === sw.value }]"
|
||||
:style="{ backgroundColor: NOTE_COLOR_HEX[sw.value] }"
|
||||
:title="sw.label"
|
||||
:aria-label="sw.label"
|
||||
:aria-selected="draftColor === sw.value"
|
||||
@click="draftColor = sw.value"
|
||||
>
|
||||
<UiIcon
|
||||
v-if="draftColor === sw.value"
|
||||
name="check-plain"
|
||||
:size="14"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<nav class="mob-toolbar mobile-only-flex">
|
||||
<button
|
||||
type="button"
|
||||
class="media-btn pin-btn"
|
||||
:class="{ on: draftPinned }"
|
||||
@click="onPinClick"
|
||||
@click="
|
||||
showChecklistEditor = !showChecklistEditor;
|
||||
if (showChecklistEditor && !draftChecklist.length)
|
||||
draftChecklist = [newChecklistItem()];
|
||||
"
|
||||
>
|
||||
سنجاق
|
||||
<UiIcon name="check" :size="20" />
|
||||
<span>چکلیست</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="showChecklistEditor" class="checklist-ed">
|
||||
<div
|
||||
v-for="(item, idx) in draftChecklist"
|
||||
:key="item.id"
|
||||
class="check-row"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="item.done"
|
||||
@change="toggleDraftCheck(item.id)"
|
||||
<div class="voice-slot">
|
||||
<VoiceToTextButton
|
||||
variant="toolbar"
|
||||
hide-error
|
||||
@transcript="(t) => (draftBody = appendSpokenText(draftBody, t))"
|
||||
/>
|
||||
<input v-model="draftChecklist[idx]!.text" type="text" placeholder="مورد" />
|
||||
<button type="button" class="icon-btn" @click="removeChecklistRow(item.id)">
|
||||
<UiIcon name="x" :size="16" />
|
||||
<button type="button" class="tiny" @click="audioInput?.click()">فایل صدا</button>
|
||||
</div>
|
||||
<button type="button" @click="imageInput?.click()">
|
||||
<UiIcon name="layers" :size="20" />
|
||||
<span>عکس</span>
|
||||
</button>
|
||||
<button type="button" @click="fileInput?.click()">
|
||||
<UiIcon name="document" :size="20" />
|
||||
<span>فایل</span>
|
||||
</button>
|
||||
<button type="button" @click="promptLocation">
|
||||
<UiIcon name="flag" :size="20" />
|
||||
<span>موقعیت</span>
|
||||
</button>
|
||||
<button type="button" @click="openMoreSheet">
|
||||
<UiIcon name="dots" :size="20" />
|
||||
<span>بیشتر</span>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div v-if="moreSheetOpen" class="sheet-root">
|
||||
<div class="sheet-backdrop" @click="moreSheetOpen = false" />
|
||||
<div class="sheet">
|
||||
<header>
|
||||
<h3>جزئیات بیشتر</h3>
|
||||
<button type="button" class="icon-btn" @click="moreSheetOpen = false">
|
||||
<UiIcon name="x" :size="18" />
|
||||
</button>
|
||||
</header>
|
||||
<label class="field">
|
||||
<span>انتخاب مشتری</span>
|
||||
<select v-model="draftPersonId">
|
||||
<option value="">—</option>
|
||||
<option v-for="p in people" :key="p.id" :value="p.id">{{ p.fullName }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>معامله</span>
|
||||
<select v-model="draftDealId">
|
||||
<option value="">—</option>
|
||||
<option v-for="d in deals" :key="d.id" :value="d.id">{{ d.title }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>فعالیت</span>
|
||||
<select v-model="draftActivityId">
|
||||
<option value="">—</option>
|
||||
<option v-for="a in activities" :key="a.id" :value="a.id">{{ a.title }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>نوع یادداشت</span>
|
||||
<select v-model="draftType">
|
||||
<option
|
||||
v-for="opt in noteTypeOptions"
|
||||
:key="opt.value"
|
||||
:value="opt.value"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>یادآوری</span>
|
||||
<JalaliDateInput v-model="draftReminder" mode="datetime" icon="bell" />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>برچسبها</span>
|
||||
<input v-model="draftTags" type="text" placeholder="برچسبها" />
|
||||
</label>
|
||||
<label class="ai-toggle">
|
||||
<input v-model="draftAnalyze" type="checkbox" />
|
||||
<div>
|
||||
<strong>تحلیل با هوش مصنوعی</strong>
|
||||
<p>پس از ذخیره اجرا میشود.</p>
|
||||
</div>
|
||||
</label>
|
||||
<button type="button" class="btn-primary sheet-done" @click="moreSheetOpen = false">
|
||||
تأیید
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="linkish" @click="addChecklistRow">+ مورد جدید</button>
|
||||
</div>
|
||||
|
||||
<div class="chip-summary">
|
||||
<span v-for="(f, i) in draftFiles" :key="`mf-${i}`" class="tag-chip">{{ f.name }}</span>
|
||||
<span v-for="t in parseTags(draftTags)" :key="t" class="tag-chip">#{{ t }}</span>
|
||||
<span v-if="draftPersonId" class="tag-chip">{{ personName(draftPersonId) }}</span>
|
||||
<span v-if="draftDealId" class="tag-chip">معامله</span>
|
||||
<span v-if="draftLocation" class="tag-chip">{{ draftLocation }}</span>
|
||||
</div>
|
||||
|
||||
<NoteAiSuggestionPanel
|
||||
v-if="editingId"
|
||||
:note-id="editingId"
|
||||
:has-person="Boolean(draftPersonId)"
|
||||
@applied="load"
|
||||
@dismissed="load"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<nav class="mob-toolbar">
|
||||
<button
|
||||
type="button"
|
||||
@click="
|
||||
showChecklistEditor = !showChecklistEditor;
|
||||
if (showChecklistEditor && !draftChecklist.length)
|
||||
draftChecklist = [newChecklistItem()];
|
||||
"
|
||||
>
|
||||
<UiIcon name="check" :size="20" />
|
||||
<span>چکلیست</span>
|
||||
</button>
|
||||
<div class="voice-slot">
|
||||
<VoiceToTextButton
|
||||
variant="toolbar"
|
||||
hide-error
|
||||
@transcript="(t) => (draftBody = appendSpokenText(draftBody, t))"
|
||||
/>
|
||||
<button type="button" class="tiny" @click="audioInput?.click()">فایل صدا</button>
|
||||
</div>
|
||||
<button type="button" @click="imageInput?.click()">
|
||||
<UiIcon name="layers" :size="20" />
|
||||
<span>عکس</span>
|
||||
</button>
|
||||
<button type="button" @click="fileInput?.click()">
|
||||
<UiIcon name="document" :size="20" />
|
||||
<span>فایل</span>
|
||||
</button>
|
||||
<button type="button" @click="promptLocation">
|
||||
<UiIcon name="flag" :size="20" />
|
||||
<span>موقعیت</span>
|
||||
</button>
|
||||
<button type="button" @click="openMoreSheet">
|
||||
<UiIcon name="dots" :size="20" />
|
||||
<span>بیشتر</span>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div v-if="moreSheetOpen" class="sheet-root">
|
||||
<div class="sheet-backdrop" @click="moreSheetOpen = false" />
|
||||
<div class="sheet">
|
||||
<header>
|
||||
<h3>جزئیات بیشتر</h3>
|
||||
<button type="button" class="icon-btn" @click="moreSheetOpen = false">
|
||||
<UiIcon name="x" :size="18" />
|
||||
</button>
|
||||
</header>
|
||||
<label class="field">
|
||||
<span>انتخاب مشتری</span>
|
||||
<select v-model="draftPersonId">
|
||||
<option value="">—</option>
|
||||
<option v-for="p in people" :key="p.id" :value="p.id">{{ p.fullName }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>معامله</span>
|
||||
<select v-model="draftDealId">
|
||||
<option value="">—</option>
|
||||
<option v-for="d in deals" :key="d.id" :value="d.id">{{ d.title }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>فعالیت</span>
|
||||
<select v-model="draftActivityId">
|
||||
<option value="">—</option>
|
||||
<option v-for="a in activities" :key="a.id" :value="a.id">{{ a.title }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>نوع یادداشت</span>
|
||||
<select v-model="draftType">
|
||||
<option
|
||||
v-for="opt in noteTypeOptions"
|
||||
:key="opt.value"
|
||||
:value="opt.value"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>یادآوری</span>
|
||||
<JalaliDateInput v-model="draftReminder" mode="datetime" icon="bell" />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>برچسبها</span>
|
||||
<input v-model="draftTags" type="text" placeholder="برچسبها" />
|
||||
</label>
|
||||
<label class="ai-toggle">
|
||||
<input v-model="draftAnalyze" type="checkbox" />
|
||||
<div>
|
||||
<strong>تحلیل با هوش مصنوعی</strong>
|
||||
<p>پس از ذخیره اجرا میشود.</p>
|
||||
</div>
|
||||
</label>
|
||||
<button type="button" class="btn-primary sheet-done" @click="moreSheetOpen = false">
|
||||
تأیید
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
</Teleport>
|
||||
</section>
|
||||
@@ -1544,8 +1438,10 @@ onBeforeUnmount(() => {
|
||||
|
||||
.notes-board.is-grid {
|
||||
margin-top: 1.1rem;
|
||||
column-count: 3;
|
||||
column-gap: 0.9rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
||||
gap: 0.85rem;
|
||||
align-items: stretch;
|
||||
}
|
||||
.notes-board.is-list {
|
||||
margin-top: 1.1rem;
|
||||
@@ -1554,21 +1450,28 @@ onBeforeUnmount(() => {
|
||||
gap: 0.75rem;
|
||||
}
|
||||
.notes-board.is-list .note-card {
|
||||
break-inside: auto;
|
||||
aspect-ratio: auto;
|
||||
min-height: 120px;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.note-card {
|
||||
break-inside: avoid;
|
||||
margin-bottom: 0.9rem;
|
||||
aspect-ratio: 1 / 1;
|
||||
width: 100%;
|
||||
min-height: 0;
|
||||
margin: 0;
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
border: 1px solid rgba(15, 23, 42, 0.05);
|
||||
padding: 0.85rem 0.9rem 0.75rem;
|
||||
padding: 0.75rem 0.8rem 0.65rem;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
text-align: start;
|
||||
transition: transform 0.12s ease, box-shadow 0.12s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.note-card:hover {
|
||||
transform: translateY(-1px);
|
||||
@@ -1581,8 +1484,6 @@ onBeforeUnmount(() => {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.4rem;
|
||||
min-height: 140px;
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
border: 1.5px dashed #cbd5e1;
|
||||
color: #64748b;
|
||||
@@ -1643,21 +1544,34 @@ onBeforeUnmount(() => {
|
||||
|
||||
.card-title {
|
||||
margin: 0 0 0.35rem;
|
||||
font-size: 1rem;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
.card-body {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
color: #334155;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.55;
|
||||
font-size: 0.82rem;
|
||||
line-height: 1.45;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 6;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
.card-check {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
@@ -1676,15 +1590,16 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
|
||||
.card-thumb {
|
||||
margin-top: 0.65rem;
|
||||
border-radius: 12px;
|
||||
margin-top: 0.45rem;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
max-height: 160px;
|
||||
flex-shrink: 0;
|
||||
max-height: 72px;
|
||||
}
|
||||
.card-thumb img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 160px;
|
||||
height: 72px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
@@ -1723,11 +1638,12 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
|
||||
.card-meta {
|
||||
margin-top: 0.7rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.35rem;
|
||||
align-items: center;
|
||||
margin-top: 0.35rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.type-badge {
|
||||
font-size: 0.72rem;
|
||||
@@ -1774,12 +1690,14 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
|
||||
.card-foot {
|
||||
margin-top: 0.55rem;
|
||||
margin-top: auto;
|
||||
padding-top: 0.45rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.72rem;
|
||||
color: #94a3b8;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.card-foot .person {
|
||||
color: #64748b;
|
||||
@@ -1810,27 +1728,40 @@ onBeforeUnmount(() => {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 80;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 1rem;
|
||||
--note-sand: #fff8e1;
|
||||
--note-rose: #fce4ec;
|
||||
--note-sky: #e3f2fd;
|
||||
--note-mint: #e0f2f1;
|
||||
--note-lavender: #f3e5f5;
|
||||
--note-default: #ffffff;
|
||||
--teal: #0d9488;
|
||||
--teal-soft: #ccfbf1;
|
||||
}
|
||||
.panel-backdrop {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(15, 23, 42, 0.35);
|
||||
background: rgba(15, 23, 42, 0.45);
|
||||
}
|
||||
.editor-panel {
|
||||
position: absolute;
|
||||
inset-block: 0;
|
||||
inset-inline-start: 0;
|
||||
width: min(420px, 94vw);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: min(520px, 100%);
|
||||
max-height: min(92vh, 840px);
|
||||
border-radius: 18px;
|
||||
background: #fff;
|
||||
box-shadow: 8px 0 40px rgba(15, 23, 42, 0.18);
|
||||
box-shadow: 0 24px 64px rgba(15, 23, 42, 0.28);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
animation: slide-in 0.22s ease;
|
||||
overflow: hidden;
|
||||
animation: modal-in 0.2s ease;
|
||||
}
|
||||
@keyframes slide-in {
|
||||
@keyframes modal-in {
|
||||
from {
|
||||
transform: translateX(-12px);
|
||||
opacity: 0.6;
|
||||
transform: translateY(10px) scale(0.98);
|
||||
opacity: 0.55;
|
||||
}
|
||||
to {
|
||||
transform: none;
|
||||
@@ -1936,15 +1867,22 @@ onBeforeUnmount(() => {
|
||||
background: #fffbeb;
|
||||
}
|
||||
|
||||
.panel-root {
|
||||
--note-sand: #fff8e1;
|
||||
--note-rose: #fce4ec;
|
||||
--note-sky: #e3f2fd;
|
||||
--note-mint: #e0f2f1;
|
||||
--note-lavender: #f3e5f5;
|
||||
--note-default: #ffffff;
|
||||
--teal: #0d9488;
|
||||
--teal-soft: #ccfbf1;
|
||||
.panel-head-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.desktop-only-flex {
|
||||
display: flex !important;
|
||||
}
|
||||
.mobile-only-flex {
|
||||
display: none !important;
|
||||
}
|
||||
.desktop-fields {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.media-row {
|
||||
@@ -2200,7 +2138,7 @@ onBeforeUnmount(() => {
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.notes-board.is-grid {
|
||||
column-count: 2;
|
||||
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2208,6 +2146,17 @@ onBeforeUnmount(() => {
|
||||
.desktop-only {
|
||||
display: none !important;
|
||||
}
|
||||
.desktop-only-flex,
|
||||
.desktop-fields {
|
||||
display: none !important;
|
||||
}
|
||||
.mobile-only-flex {
|
||||
display: flex !important;
|
||||
}
|
||||
.chip-summary.mobile-only-flex {
|
||||
flex-wrap: wrap;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
.mobile-quick.mobile-only,
|
||||
.chips.mobile-only {
|
||||
display: flex !important;
|
||||
@@ -2216,18 +2165,24 @@ onBeforeUnmount(() => {
|
||||
display: inline-flex !important;
|
||||
}
|
||||
.notes-board.is-grid {
|
||||
column-count: 2;
|
||||
column-gap: 0.65rem;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0.65rem;
|
||||
}
|
||||
.note-card {
|
||||
padding: 0.7rem;
|
||||
margin-bottom: 0.65rem;
|
||||
padding: 0.65rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 861px) {
|
||||
.mobile-editor {
|
||||
display: none !important;
|
||||
.editor-panel {
|
||||
width: min(100%, 520px);
|
||||
max-height: 94vh;
|
||||
border-radius: 16px;
|
||||
}
|
||||
.panel-root {
|
||||
padding: 0.5rem;
|
||||
place-items: center;
|
||||
}
|
||||
.btn-save.mobile-only-flex {
|
||||
padding: 0.4rem 0.85rem;
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user