Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions docs/app/components/content/examples/form/FormTaskFormExample.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<script setup lang="ts">
import type { EditorToolbarItem, IconComponent } from '@bitrix24/b24ui-nuxt'
import { CalendarDate } from '@internationalized/date'
import FileUploadIcon from '@bitrix24/b24icons-vue/main/FileUploadIcon'
import GoToLIcon from '@bitrix24/b24icons-vue/outline/GoToLIcon'
import PersonIcon from '@bitrix24/b24icons-vue/main/PersonIcon'
import MentionIcon from '@bitrix24/b24icons-vue/outline/MentionIcon'
import BulletedListIcon from '@bitrix24/b24icons-vue/outline/BulletedListIcon'
import NumberedListIcon from '@bitrix24/b24icons-vue/outline/NumberedListIcon'
import PlusLIcon from '@bitrix24/b24icons-vue/outline/PlusLIcon'
import CalendarIcon from '@bitrix24/b24icons-vue/outline/CalendarIcon'
import CircleCheckIcon from '@bitrix24/b24icons-vue/outline/CircleCheckIcon'
import TaskListIcon from '@bitrix24/b24icons-vue/outline/TaskListIcon'
import FolderPlusIcon from '@bitrix24/b24icons-vue/outline/FolderPlusIcon'
import UserGroupIcon from '@bitrix24/b24icons-vue/common-b24/UserGroupIcon'
import NotificationIcon from '@bitrix24/b24icons-vue/outline/NotificationIcon'
import BusinesProcessStagesIcon from '@bitrix24/b24icons-vue/outline/BusinesProcessStagesIcon'
import PinIcon from '@bitrix24/b24icons-vue/outline/PinIcon'
import BellIcon from '@bitrix24/b24icons-vue/main/BellIcon'
import ItemIcon from '@bitrix24/b24icons-vue/crm/ItemIcon'
import ArrowTopLIcon from '@bitrix24/b24icons-vue/outline/ArrowTopLIcon'
import ArrowDownLIcon from '@bitrix24/b24icons-vue/outline/ArrowDownLIcon'
import LinkIcon from '@bitrix24/b24icons-vue/outline/LinkIcon'
import LayersIcon from '@bitrix24/b24icons-vue/outline/LayersIcon'
import ClockIcon from '@bitrix24/b24icons-vue/outline/ClockIcon'
import SettingsIcon from '@bitrix24/b24icons-vue/outline/SettingsIcon'

const title = ref('Design the new task form interface')
const description = ref('')
const deadline = shallowRef<CalendarDate | undefined>(new CalendarDate(2026, 6, 30))
const deadlineInput = useTemplateRef('deadlineInput')

const toolbarItems: EditorToolbarItem[][] = [[
{ kind: 'mention', icon: MentionIcon, tooltip: { text: 'Mention' } },
{ kind: 'bulletList', icon: BulletedListIcon, tooltip: { text: 'Bullet list' } },
{ kind: 'orderedList', icon: NumberedListIcon, tooltip: { text: 'Numbered list' } }
]]

const actionButtons: { label: string, icon: IconComponent, active?: boolean }[] = [
{ label: 'Results', icon: CircleCheckIcon, active: true },
{ label: 'Files', icon: FileUploadIcon, active: true },
{ label: 'Checklists', icon: TaskListIcon },
{ label: 'Project', icon: FolderPlusIcon },
{ label: 'Co-executors', icon: UserGroupIcon },
{ label: 'Observers', icon: NotificationIcon },
{ label: 'Flow', icon: BusinesProcessStagesIcon },
{ label: 'Tags', icon: PinIcon, active: true },
{ label: 'Reminders', icon: BellIcon },
{ label: 'CRM elements', icon: ItemIcon },
{ label: 'Parent task', icon: ArrowTopLIcon },
{ label: 'Subtasks', icon: ArrowDownLIcon },
{ label: 'Linked tasks', icon: LinkIcon },
{ label: 'Gantt', icon: LayersIcon },
{ label: 'Timeline planning', icon: CalendarIcon },
{ label: 'Time tracking', icon: ClockIcon },
{ label: 'Custom fields', icon: SettingsIcon }
]
</script>

<template>
<div class="flex flex-col gap-4 p-4 w-full">
<B24Input
v-model="title"
placeholder="Task name"
size="xl"
no-border
:b24ui="{ base: 'font-(--ui-font-weight-semi-bold)' }"
/>

<B24Card :b24ui="{ body: 'p-0' }">
<B24Editor
v-slot="{ editor }"
v-model="description"
content-type="markdown"
placeholder="Add a task description..."
:b24ui="{ base: 'min-h-48 px-4 py-3' }"
>
<div class="flex items-center gap-1 px-2 py-1.5 border-b border-(--ui-color-divider-default)">
<B24Button :icon="FileUploadIcon" color="air-tertiary" variant="ghost" size="sm" aria-label="Attach file" />
<B24EditorToolbar :editor="editor" :items="toolbarItems" />
<div class="ml-auto">
<B24Button :icon="GoToLIcon" color="air-tertiary" variant="ghost" size="sm" aria-label="Expand editor" />
</div>
</div>
</B24Editor>
</B24Card>

<B24Card :b24ui="{ body: 'p-0' }">
<div class="divide-y divide-(--ui-color-divider-default)">
<div class="flex items-center gap-3 px-5 py-3">
<span class="text-description text-sm w-28 shrink-0">Creator</span>
<div class="flex items-center gap-2 min-w-0">
<B24Avatar :icon="PersonIcon" color="air-secondary-accent-2" size="xs" />
<span class="text-sm truncate">Jane Cooper</span>
</div>
</div>
<div class="flex items-center gap-3 px-5 py-3">
<span class="text-description text-sm w-28 shrink-0">Assignee</span>
<div class="flex items-center gap-2 min-w-0">
<B24Avatar :icon="PersonIcon" color="air-secondary-alert" size="xs" />
<span class="text-sm truncate">Unassigned</span>
</div>
</div>
<div class="flex items-center gap-3 px-5 py-3">
<span class="text-description text-sm w-28 shrink-0">Deadline</span>
<B24InputDate ref="deadlineInput" v-model="deadline" size="sm" no-border class="flex-1">
<template #trailing>
<B24Popover :reference="deadlineInput?.inputsRef[3]?.$el">
<B24Button
color="air-tertiary-no-accent"
size="sm"
:icon="CalendarIcon"
aria-label="Pick a date"
class="px-0"
/>
<template #content>
<B24Calendar v-model="deadline" class="p-2" />
</template>
</B24Popover>
</template>
</B24InputDate>
</div>
</div>
</B24Card>

<B24Card>
<template #header>
<div class="flex items-center justify-between">
<span class="text-sm font-(--ui-font-weight-medium)">Watchers</span>
<B24Button :icon="PlusLIcon" color="air-tertiary" variant="ghost" size="xs" aria-label="Add watcher" />
</div>
</template>
<div class="flex flex-wrap gap-2">
<B24Avatar :icon="PersonIcon" color="air-secondary-accent-2" size="xs" />
<B24Avatar :icon="PersonIcon" color="air-secondary-alert" size="xs" />
<B24Avatar :icon="PersonIcon" color="air-secondary" size="xs" />
</div>
</B24Card>

<div class="flex flex-wrap gap-2">
<B24Button
v-for="btn in actionButtons"
:key="btn.label"
:icon="btn.icon"
:label="btn.label"
:color="btn.active ? 'air-secondary-accent-2' : 'air-secondary-no-accent'"
:aria-pressed="btn.active ? 'true' : 'false'"
size="sm"
/>
</div>

<div class="flex gap-2 justify-end">
<B24Button label="Save" color="air-primary" />
<B24Button label="Cancel" color="air-tertiary" />
</div>
</div>
</template>
34 changes: 34 additions & 0 deletions docs/content/docs/2.components/form.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ name: 'form-example-nested-list'
---
::

## Examples

### Record edit section

A common record-edit pattern (UF placement, slider context): a titled section with vertical-label fields, a two-column row for amount + currency, a nested "Client" sub-section, and a series of additional fields. Built entirely from `B24Form`, `B24FormField`, `B24Input`, `B24Select`, `B24InputNumber`, `B24InputDate`, `B24Popover` and `B24Calendar` — no custom components.
Expand Down Expand Up @@ -259,6 +261,38 @@ Once those answers are in:
Keep all copy in the requested locale.
::

### Task form layout

Real-world example: a Bitrix24-style task form assembled from standard components only — `Input` for the title, `Editor` (with a minimal toolbar row) for the description, `Card`, `Avatar`, and `InputDate` for the responsible-persons block, and a wrap row of `Button` actions. Single-column layout throughout — no custom CSS beyond component props.

::component-example
---
collapse: true
name: 'form-task-form-example'
class: '!p-0'
---
::

::prompt
---
description: Build a Bitrix24-style task form using standard b24ui components.
actions:
- copy
- cursor
- windsurf
class: 'w-full my-0'
---
Build a Bitrix24-style task form layout using only standard `b24ui` components (single column, no custom CSS beyond component props).

- **Title**: `B24Input` `size="xl"` `no-border`, bold via `:b24ui="{ base: 'font-(--ui-font-weight-semi-bold)' }"`
- **Editor card**: `B24Card` with `b24ui.body='p-0'` containing `B24Editor` (`content-type="markdown"`, `min-h-48 px-4 py-3`). Inside the editor's default slot, render a toolbar row (`flex items-center gap-1 px-2 py-1.5 border-b`): attachment `B24Button` on the left, `B24EditorToolbar` with `mention`/`bulletList`/`orderedList` in the middle, expand `B24Button` (`GoToLIcon`) pushed to `ml-auto`
- **Responsible persons card**: `B24Card` `b24ui.body='p-0'`, body is a `divide-y` div with three `px-5 py-3` rows — Creator (`B24Avatar` + name), Assignee (`B24Avatar` + name), Deadline (`B24InputDate` `size="sm"` `no-border` with `B24Popover`+`B24Calendar` in the `#trailing` slot, both sharing the same `shallowRef<CalendarDate | undefined>`)
- **Watchers card**: `#header` with label and `+` `B24Button`; body shows `B24Avatar` icons
- **Action buttons**: `flex flex-wrap gap-2` row of 17 `B24Button` `size="sm"` — each item has an `active` flag; active → `color="air-secondary-accent-2"`, inactive → `color="air-secondary-no-accent"`. Buttons: Results, Files, Checklists, Project, Co-executors, Observers, Flow, Tags, Reminders, CRM elements, Parent task, Subtasks, Linked tasks, Gantt, Timeline planning, Time tracking, Custom fields
- **Footer**: `flex gap-2 justify-end` with Save (`air-primary`) and Cancel (`air-tertiary`)
- State: `title` and `description` as `ref`; `deadline` as `shallowRef<CalendarDate | undefined>` (from `@internationalized/date` — `B24InputDate` does not accept native `Date`); `toolbarItems` as a plain `const` (no reactive deps); action list typed as `{ label: string, icon: IconComponent, active?: boolean }[]`
::

## API

### Props
Expand Down
10 changes: 10 additions & 0 deletions playgrounds/demo/app/pages/components/form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import FormExampleNested from '../../../../../docs/app/components/content/exampl
import FormExampleNestedList from '../../../../../docs/app/components/content/examples/form/FormExampleNestedList.vue'
import FormExampleElements from '../../../../../docs/app/components/content/examples/form/FormExampleElements.vue'
import FormExampleEditSection from '../../../../../docs/app/components/content/examples/form/FormExampleEditSection.vue'
import FormTaskFormExample from '../../../../../docs/app/components/content/examples/form/FormTaskFormExample.vue'

const validateOn = ref(['input', 'change', 'blur'])
const disabled = ref(false)
Expand Down Expand Up @@ -69,6 +70,15 @@ const disabled = ref(false)
</template>
<FormExampleElements :validate-on="validateOn" :disabled="disabled" />
</B24Card>

<B24Card :variant="cardVariant" :class="[cardBorderClass, 'grow', 'max-w-[41.6rem]']">
<template #header>
<ProseH5 class="mb-0">
Task form layout
</ProseH5>
</template>
<FormTaskFormExample />
</B24Card>
</template>
</PlaygroundPage>
</template>
10 changes: 10 additions & 0 deletions playgrounds/nuxt/app/pages/components/form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import FormExampleNested from '../../../../../docs/app/components/content/exampl
import FormExampleNestedList from '../../../../../docs/app/components/content/examples/form/FormExampleNestedList.vue'
import FormExampleElements from '../../../../../docs/app/components/content/examples/form/FormExampleElements.vue'
import FormExampleEditSection from '../../../../../docs/app/components/content/examples/form/FormExampleEditSection.vue'
import FormTaskFormExample from '../../../../../docs/app/components/content/examples/form/FormTaskFormExample.vue'

const validateOn = ref(['input', 'change', 'blur'])
const disabled = ref(false)
Expand Down Expand Up @@ -69,6 +70,15 @@ const disabled = ref(false)
</template>
<FormExampleElements :validate-on="validateOn" :disabled="disabled" />
</B24Card>

<B24Card :variant="cardVariant" :class="[cardBorderClass, 'grow', 'max-w-[41.6rem]']">
<template #header>
<ProseH5 class="mb-0">
Task form layout
</ProseH5>
</template>
<FormTaskFormExample />
</B24Card>
</template>
</PlaygroundPage>
</template>
Loading