diff --git a/CHANGELOG.md b/CHANGELOG.md index f9f154a7..b9ec2b39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- **Quick-create regular and temporary notes from the Home and Space screens.** + The Home screen now shows a second action next to "New note" that creates a + *temporary* note (one that auto-moves to Trash after the workspace lifetime), + resolving the target space the same way the regular button does — created + directly when you can write to a single space, or via a space picker when + several. Each space overview screen gains two buttons — "New note" and "New + temporary note" — that create the page directly in that space and open it, + mirroring the existing space-sidebar actions and shown only to members who can + manage pages. - **Interrupt the AI agent and send a queued message now.** A queued AI-chat message gains a "send now" action that interrupts the streaming turn and immediately sends that message, keeping the agent's partial output. The diff --git a/README.md b/README.md index 9f9982cb..cbbbdcab 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ community feature, with no enterprise license. Open it from the page header; the - ✅ **Page templates** — flag a page as a template and embed its whole content live into other pages; edits to the template propagate to every place it is inserted (whole-page transclusion on top of the existing synced blocks). - ✅ **Public-share AI assistant** — anonymous visitors of a shared page can ask the AI agent, scoped strictly to that share's page tree (read-only, share-scoped search), behind a workspace toggle. - ✅ **Footnotes** — academic-style footnotes: a numbered superscript reference inline (read it in place via a hover popover), with the note text living as a real, editable block at the bottom of the page; auto-numbered, collaboration-safe, and round-trips through Markdown export/import and the AI agent / MCP. +- ✅ **Temporary notes** — mark a note as temporary and it auto-moves to Trash after a configurable per-workspace lifetime (default 24h) unless made permanent first; create one in a click from the Home screen, any space overview, or the space sidebar, with a "Make permanent" rescue banner on the open note. ### In progress diff --git a/README.ru.md b/README.ru.md index d659d2fb..132ba442 100644 --- a/README.ru.md +++ b/README.ru.md @@ -105,6 +105,7 @@ real-time-коллаборации Docmost, поэтому запись нико - ✅ **Шаблоны страниц** — пометить страницу шаблоном и вставлять её содержимое живой ссылкой в другие страницы; правки шаблона распространяются на все места вставки (whole-page-транслюзия поверх существующих synced-блоков). - ✅ **AI-ассистент на публичных шарах** — анонимный зритель расшаренной страницы может спросить AI-агента, который ищет строго по дереву этой шары (read-only, share-scoped поиск), за тумблером воркспейса. - ✅ **Сноски** — сноски академического вида: нумерованная ссылка-надстрочник прямо в тексте (читается на месте во всплывающем окне по наведению), а текст сноски живёт реальным редактируемым блоком внизу страницы; авто-нумерация, безопасна для совместного редактирования, переживает экспорт/импорт Markdown и доступна AI-агенту / MCP. +- ✅ **Временные заметки** — пометьте заметку временной, и она автоматически уедет в корзину по истечении настраиваемого срока жизни воркспейса (по умолчанию 24 ч), если её предварительно не сделать постоянной; создать такую можно в один клик с домашнего экрана, с обзора любого пространства или из сайдбара пространства, а на открытой заметке есть баннер «Сделать постоянной». ### В процессе diff --git a/apps/client/src/features/home/components/new-note-button.tsx b/apps/client/src/features/home/components/new-note-button.tsx index ce58a604..69bcac37 100644 --- a/apps/client/src/features/home/components/new-note-button.tsx +++ b/apps/client/src/features/home/components/new-note-button.tsx @@ -1,5 +1,6 @@ -import { Button, Menu, Text } from "@mantine/core"; -import { IconPlus } from "@tabler/icons-react"; +import { Button, Group, Menu, Text } from "@mantine/core"; +import { IconHourglass, IconPlus } from "@tabler/icons-react"; +import { ReactNode } from "react"; import { useNavigate } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { useGetSpacesQuery } from "@/features/space/queries/space-query.ts"; @@ -10,24 +11,34 @@ import { CustomAvatar } from "@/components/ui/custom-avatar.tsx"; import { AvatarIconType } from "@/features/attachments/types/attachment.types.ts"; import { canCreatePage } from "./can-create-page.ts"; -// Prominent home-screen action to create a new note (page). Because the home -// screen has no active space, the target space is resolved from the user's -// writable spaces: created directly when there is one, picked from a dropdown -// when there are several. -export default function NewNoteButton() { +// A single create-note action, parametrized by `temporary`. Self-contained: it +// owns its own create mutation so the regular and temporary buttons show +// independent loading state, while the list of writable spaces is resolved once +// by the parent and passed in. With exactly one writable space it creates +// directly; with several it shows a target-space picker. +function CreateNoteButton({ + writableSpaces, + temporary, + label, + icon, +}: { + writableSpaces: ISpace[]; + temporary: boolean; + label: string; + icon: ReactNode; +}) { const { t } = useTranslation(); const navigate = useNavigate(); const createPageMutation = useCreatePageMutation(); - const { data } = useGetSpacesQuery({ limit: 100 }); - - const writableSpaces = (data?.items ?? []).filter(canCreatePage); const createNote = async (space: ISpace) => { try { - // `spaceId` is accepted by the create-page endpoint but is not part of - // the shared `IPageInput` type; cast to satisfy the mutation signature. + // `spaceId`/`temporary` are accepted by the create-page endpoint but are + // not part of the shared `IPageInput` type; cast to satisfy the mutation + // signature. const createdPage = await createPageMutation.mutateAsync({ spaceId: space.id, + ...(temporary ? { temporary: true } : {}), } as any); navigate(buildPageUrl(space.slug, createdPage.slugId, createdPage.title)); } catch { @@ -35,24 +46,20 @@ export default function NewNoteButton() { } }; - // No writable space → nothing to create in; render nothing. - if (writableSpaces.length === 0) return null; - const isPending = createPageMutation.isPending; // Exactly one writable space → create directly, no picker needed. if (writableSpaces.length === 1) { return ( } + leftSection={icon} loading={isPending} onClick={() => createNote(writableSpaces[0])} > - {t("New note")} + {label} ); } @@ -62,14 +69,13 @@ export default function NewNoteButton() {
); } + +// Prominent home-screen actions to create a new note (page). Because the home +// screen has no active space, the target space is resolved from the user's +// writable spaces: created directly when there is one, picked from a dropdown +// when there are several. Renders two equal-width buttons: a regular note and a +// temporary note (which auto-moves to Trash after the workspace lifetime). +export default function NewNoteButton() { + const { t } = useTranslation(); + const { data } = useGetSpacesQuery({ limit: 100 }); + + const writableSpaces = (data?.items ?? []).filter(canCreatePage); + + // No writable space → nothing to create in; render nothing. + if (writableSpaces.length === 0) return null; + + return ( +