Skip to content

Commit bff9646

Browse files
authored
Merge pull request #15 from Dobrunia/main
fix
2 parents dbf821c + bf9deef commit bff9646

18 files changed

Lines changed: 363 additions & 104 deletions

File tree

client/src/App.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ watch(
3333
<template>
3434
<CookieConsent v-if="!cookieConsent.accepted" />
3535
<template v-else>
36-
<div class="min-h-screen bg-bg">
36+
<div class="min-h-screen">
3737
<AppHeader />
38-
<main :class="authStore.user ? 'pt-25' : 'pt-14'">
38+
<main :class="authStore.user ? 'pt-[126px]' : 'pt-[63px]'">
3939
<RouterView />
4040
</main>
4141
<Toaster position="bottom-right" />

client/src/assets/main.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
--fg: 17 24 39;
1616

1717
--surface: 255 255 255;
18-
--border: 229 231 235;
18+
--border: 209 211 215;
1919
--muted: 107 114 128;
2020

2121
--primary: 59 130 246;

client/src/components/card/CreateCardDialog.vue

Lines changed: 104 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const checklistItems = ref<ChecklistItem[]>([]);
6464
const checklistSummary = ref('');
6565
const tagsInput = ref('');
6666
const loading = ref(false);
67+
const submitted = ref(false);
6768
const checklistListRef = ref<HTMLElement | null>(null);
6869
const titleInputRef = ref<HTMLInputElement | null>(null);
6970
let checklistSortable: Sortable | null = null;
@@ -105,19 +106,24 @@ watch(
105106
title.value = card.title ?? '';
106107
cardType.value = card.type as 'NOTE' | 'LINK' | 'CHECKLIST';
107108
try {
108-
const pl = typeof card.payload === 'string' ? JSON.parse(card.payload || '{}') : card.payload;
109+
const pl =
110+
typeof card.payload === 'string' ? JSON.parse(card.payload || '{}') : card.payload;
109111
if (card.type === 'NOTE') {
110112
noteContent.value = (pl as { content?: string }).content ?? '';
111113
noteSummary.value = (pl as { summary?: string }).summary ?? '';
112114
} else if (card.type === 'LINK') {
113115
linkUrl.value = (pl as { url?: string }).url ?? '';
114116
linkSummary.value = (pl as { summary?: string }).summary ?? '';
115117
} else if (card.type === 'CHECKLIST') {
116-
const items = (pl as { items?: { id: string; text: string; done: boolean; order: number }[] }).items ?? [];
117-
checklistItems.value = items.length ? items.map((i) => ({ ...i })) : [{ id: crypto.randomUUID(), text: '', done: false, order: 100 }];
118+
const items =
119+
(pl as { items?: { id: string; text: string; done: boolean; order: number }[] })
120+
.items ?? [];
121+
checklistItems.value = items.length
122+
? items.map((i) => ({ ...i }))
123+
: [{ id: crypto.randomUUID(), text: '', done: false, order: 100 }];
118124
checklistSummary.value = (pl as { summary?: string }).summary ?? '';
119125
}
120-
tagsInput.value = Array.isArray(card.tags) ? card.tags.join(', ') : '';
126+
tagsInput.value = Array.isArray(card.tags) ? card.tags.join(', ') : '';
121127
} catch {
122128
noteContent.value = '';
123129
noteSummary.value = '';
@@ -141,6 +147,7 @@ watch(
141147
tagsInput.value = '';
142148
if (!props.columnId && props.workspaceId == null) workspaceStore.fetchWorkspaces();
143149
}
150+
submitted.value = false;
144151
nextTick(() => {
145152
initChecklistSortable();
146153
titleInputRef.value?.focus();
@@ -165,7 +172,9 @@ onUnmounted(() => {
165172
});
166173
167174
function addChecklistItem() {
168-
const maxOrder = checklistItems.value.length ? Math.max(...checklistItems.value.map((i) => i.order)) : 0;
175+
const maxOrder = checklistItems.value.length
176+
? Math.max(...checklistItems.value.map((i) => i.order))
177+
: 0;
169178
checklistItems.value.push({
170179
id: crypto.randomUUID(),
171180
text: '',
@@ -219,6 +228,8 @@ function buildPayload(): string {
219228
}
220229
221230
async function handleSubmit() {
231+
submitted.value = true;
232+
222233
if (cardType.value === 'LINK' && !linkUrl.value.trim()) {
223234
toast.error('Введите URL ссылки');
224235
return;
@@ -282,7 +293,10 @@ async function handleSubmit() {
282293
<DialogRoot v-model:open="openProxy">
283294
<DialogPortal>
284295
<DialogOverlay class="dialog-overlay" @click="openProxy = false" />
285-
<DialogContent class="dialog-content max-h-[90vh] overflow-y-auto" @escape-key-down="openProxy = false">
296+
<DialogContent
297+
class="dialog-content max-h-[90vh] overflow-y-auto"
298+
@escape-key-down="openProxy = false"
299+
>
286300
<div class="dialog-header">
287301
<DialogTitle class="dialog-title">
288302
{{ isEditMode ? 'Редактировать карточку' : 'Новая карточка' }}
@@ -298,39 +312,54 @@ async function handleSubmit() {
298312
<div class="flex gap-2 mb-3">
299313
<button
300314
type="button"
301-
class="flex-1 h-9 px-3 text-sm rounded-[var(--r)] flex-center gap-1.5 transition-colors"
302-
:class="addDestination === 'hub' ? 'bg-primary text-on-primary' : 'bg-surface border border-border text-muted hover:text-fg'"
303-
@click="addDestination = 'hub'; selectedWorkspaceId = ''"
315+
class="flex-1 h-9 px-3 border border-border text-sm rounded-[var(--r)] flex-center gap-1.5 transition-colors"
316+
:class="
317+
addDestination === 'hub'
318+
? 'bg-primary text-on-primary'
319+
: 'bg-surface text-muted hover:text-fg'
320+
"
321+
@click="
322+
addDestination = 'hub';
323+
selectedWorkspaceId = '';
324+
"
304325
>
305326
<span class="i-lucide-inbox" />
306327
Хаб
307328
</button>
308329
<button
309330
type="button"
310-
class="flex-1 h-9 px-3 text-sm rounded-[var(--r)] flex-center gap-1.5 transition-colors"
311-
:class="addDestination === 'workspace' ? 'bg-primary text-on-primary' : 'bg-surface border border-border text-muted hover:text-fg'"
331+
class="flex-1 h-9 px-3 border border-border text-sm rounded-[var(--r)] flex-center gap-1.5 transition-colors"
332+
:class="
333+
addDestination === 'workspace'
334+
? 'bg-primary text-on-primary'
335+
: 'bg-surface text-muted hover:text-fg'
336+
"
312337
@click="addDestination = 'workspace'"
313338
>
314339
<span class="i-lucide-layout-grid" />
315340
Воркспейс
316341
</button>
317342
</div>
318-
<div v-if="addDestination === 'workspace'" class="mt-2">
319-
<label for="card-workspace" class="block text-sm text-muted mb-1">Воркспейс (карточка попадёт в беклог)</label>
320-
<select
321-
id="card-workspace"
322-
v-model="selectedWorkspaceId"
323-
class="input py-2 max-w-full truncate"
324-
>
325-
<option value="" disabled hidden>Выберите воркспейс</option>
326-
<option
327-
v-for="w in workspaces"
328-
:key="w.id"
329-
:value="w.id"
343+
<div class="mt-2 h-[72px]">
344+
<template v-if="addDestination === 'hub'">
345+
<p class="text-sm text-muted text-center h-full flex-center">Карточка попадёт в общий список без привязки к воркспейсу</p>
346+
</template>
347+
<template v-else>
348+
<label for="card-workspace" class="block text-sm text-muted mb-1"
349+
>Воркспейс * (карточка попадёт в беклог)</label
350+
>
351+
<select
352+
id="card-workspace"
353+
v-model="selectedWorkspaceId"
354+
class="input py-2 max-w-full truncate"
355+
:class="submitted && !selectedWorkspaceId && 'border-danger!'"
330356
>
331-
{{ w.title.length > 40 ? w.title.slice(0, 40) + '…' : w.title }}
332-
</option>
333-
</select>
357+
<option value="" disabled hidden>Выберите воркспейс</option>
358+
<option v-for="w in workspaces" :key="w.id" :value="w.id">
359+
{{ w.title.length > 40 ? w.title.slice(0, 40) + '…' : w.title }}
360+
</option>
361+
</select>
362+
</template>
334363
</div>
335364
</div>
336365

@@ -346,17 +375,6 @@ async function handleSubmit() {
346375
/>
347376
</div>
348377

349-
<div>
350-
<label for="card-tags" class="block text-sm font-medium mb-1">Теги</label>
351-
<input
352-
id="card-tags"
353-
v-model="tagsInput"
354-
type="text"
355-
class="input"
356-
placeholder="Через запятую, например: работа, идеи"
357-
/>
358-
</div>
359-
360378
<div v-if="!isEditMode">
361379
<label class="block text-sm font-medium mb-2">Тип</label>
362380
<div class="flex gap-2">
@@ -365,8 +383,12 @@ async function handleSubmit() {
365383
:key="t.value"
366384
type="button"
367385
@click="cardType = t.value"
368-
class="flex-1 h-9 px-3 text-sm rounded-[var(--r)] flex-center gap-1.5 transition-colors"
369-
:class="cardType === t.value ? 'bg-primary text-on-primary' : 'bg-surface border border-border text-muted hover:text-fg'"
386+
class="flex-1 h-9 px-3 border border-border text-sm rounded-[var(--r)] flex-center gap-1.5 transition-colors"
387+
:class="
388+
cardType === t.value
389+
? 'bg-primary text-on-primary'
390+
: 'bg-surface text-muted hover:text-fg'
391+
"
370392
>
371393
<span :class="t.icon" />
372394
{{ t.label }}
@@ -375,7 +397,7 @@ async function handleSubmit() {
375397
</div>
376398

377399
<template v-if="cardType === 'NOTE'">
378-
<div>
400+
<div class="min-h-[152px]">
379401
<label for="card-note" class="block text-sm font-medium mb-1">Текст заметки</label>
380402
<textarea
381403
id="card-note"
@@ -385,7 +407,17 @@ async function handleSubmit() {
385407
/>
386408
</div>
387409
<div>
388-
<label for="card-summary-note" class="block text-sm font-medium mb-1">Конспект</label>
410+
<label for="card-tags-note" class="block text-sm font-medium mb-1">Теги</label>
411+
<input
412+
id="card-tags-note"
413+
v-model="tagsInput"
414+
type="text"
415+
class="input"
416+
placeholder="Через запятую: работа, идеи"
417+
/>
418+
</div>
419+
<div>
420+
<label for="card-summary-note" class="block text-sm font-medium mb-1">Заметка</label>
389421
<input
390422
id="card-summary-note"
391423
v-model="noteSummary"
@@ -397,18 +429,29 @@ async function handleSubmit() {
397429
</template>
398430

399431
<template v-if="cardType === 'LINK'">
400-
<div>
432+
<div class="min-h-[152px]">
401433
<label for="card-url" class="block text-sm font-medium mb-1">URL *</label>
402434
<input
403435
id="card-url"
404436
v-model="linkUrl"
405437
type="url"
406438
class="input"
439+
:class="submitted && !linkUrl.trim() && 'border-danger!'"
407440
placeholder="https://..."
408441
/>
409442
</div>
410443
<div>
411-
<label for="card-summary-link" class="block text-sm font-medium mb-1">Конспект</label>
444+
<label for="card-tags-link" class="block text-sm font-medium mb-1">Теги</label>
445+
<input
446+
id="card-tags-link"
447+
v-model="tagsInput"
448+
type="text"
449+
class="input"
450+
placeholder="Через запятую: работа, идеи"
451+
/>
452+
</div>
453+
<div>
454+
<label for="card-summary-link" class="block text-sm font-medium mb-1">Заметка</label>
412455
<input
413456
id="card-summary-link"
414457
v-model="linkSummary"
@@ -420,15 +463,17 @@ async function handleSubmit() {
420463
</template>
421464

422465
<template v-if="cardType === 'CHECKLIST'">
423-
<div>
466+
<div class="min-h-[152px]">
424467
<label class="block text-sm font-medium mb-2">Пункты</label>
425468
<div ref="checklistListRef" class="space-y-2">
426469
<div
427470
v-for="(item, index) in checklistItems"
428471
:key="item.id"
429472
class="flex items-center gap-2"
430473
>
431-
<span class="checklist-grip i-lucide-grip-vertical text-muted cursor-grab active:cursor-grabbing" />
474+
<span
475+
class="checklist-grip i-lucide-grip-vertical text-muted cursor-grab active:cursor-grabbing"
476+
/>
432477
<input
433478
v-model="item.text"
434479
type="text"
@@ -455,7 +500,19 @@ async function handleSubmit() {
455500
</button>
456501
</div>
457502
<div>
458-
<label for="card-summary-checklist" class="block text-sm font-medium mb-1">Конспект</label>
503+
<label for="card-tags-checklist" class="block text-sm font-medium mb-1">Теги</label>
504+
<input
505+
id="card-tags-checklist"
506+
v-model="tagsInput"
507+
type="text"
508+
class="input"
509+
placeholder="Через запятую: работа, идеи"
510+
/>
511+
</div>
512+
<div>
513+
<label for="card-summary-checklist" class="block text-sm font-medium mb-1"
514+
>Заметка</label
515+
>
459516
<input
460517
id="card-summary-checklist"
461518
v-model="checklistSummary"
@@ -467,12 +524,7 @@ async function handleSubmit() {
467524
</template>
468525

469526
<div class="flex justify-between items-center gap-3 pt-4">
470-
<button
471-
v-if="isEditMode"
472-
type="button"
473-
class="btn-delete"
474-
@click="emit('delete')"
475-
>
527+
<button v-if="isEditMode" type="button" class="btn-delete" @click="emit('delete')">
476528
<span class="i-lucide-trash-2" />
477529
Удалить
478530
</button>

0 commit comments

Comments
 (0)