Разработка кастомных интерфейсов Directus
Стандартные поля ввода Directus — текст, число, дата — не покрывают 30% реальных сценариев. Когда клиенту нужен выбор цвета из корпоративной палитры Pantone, рейтинг звёздами из 10 или интерактивная карта для указания координат, приходится либо извращаться с JSON-полем, либо писать кастомный интерфейс. Второе — правильный путь. В одном проекте мы заменили 15 стандартных полей на кастомные интерфейсы, что сократило время заполнения каталога на 40%.
Недавний пример: заказчик хотел поле для выбора цвета строго из утверждённых оттенков бренда — стандартный color picker допускал любые hex-коды. Мы разработали компонент, который отображает только корпоративные цвета и блокирует ввод произвольных значений. Это сократило количество ошибок при заполнении каталога в разы.
Мы создаём уникальные Vue-3-компоненты для полей админки Directus. Каждый интерфейс — это полноценное расширение (Directus interface extension), которое легко поддерживать, переиспользовать и настраивать под бизнес-логику. За 5 лет работы мы реализовали 20+ таких интерфейсов — от простых color picker до сложных с асинхронной загрузкой данных. Получите оценку вашего проекта на встрече с нашим инженером.
Как создать кастомный интерфейс в Directus?
Стандартный интерфейс — это Vue-3-компонент, зарегистрированный через create-directus-extension. Например, color picker:
Пример кода color picker
npx create-directus-extension@latest
# Type: interface
# Name: color-picker
cd directus-extension-interface-color-picker
npm install
npm run dev
# режим разработки с hot reloadСам компонент использует Composition API, принимает value, placeholder и эмитит input:
<!-- src/interface.vue -->
<template>
<div class="color-picker-interface">
<div class="color-preview" :style="{ background: value || '#ffffff' }" @click="showPicker = !showPicker" />
<v-input :model-value="value" type="text" :placeholder="placeholder || '#000000'" @update:model-value="$emit('input', $event)" />
<div v-if="showPicker" class="color-grid">
<div v-for="color in presetColors" :key="color" class="color-swatch" :style="{ background: color }" :class="{ active: value === color }" @click="selectColor(color)" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const props = defineProps<{
value: string | null
placeholder?: string
presetColors?: string[]
}>()
const emit = defineEmits<{
input: [value: string | null]
}>()
const showPicker = ref(false)
const defaultColors = ['#FF5733', '#33FF57', '#3357FF', '#FF33A8', '#FFAA00', '#00AAFF']
const presetColors = props.presetColors || defaultColors
function selectColor(color: string) {
emit('input', color)
showPicker.value = false
}
</script>
<style scoped>
.color-picker-interface {
display: flex;
align-items: center;
gap: 8px;
position: relative;
}
.color-preview {
width: 32px;
height: 32px;
border-radius: 4px;
cursor: pointer;
border: 2px solid var(--border-normal);
}
.color-grid {
position: absolute;
top: 100%;
left: 0;
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 4px;
padding: 8px;
background: var(--background-page);
border: 1px solid var(--border-normal);
border-radius: 4px;
z-index: 100;
}
.color-swatch {
width: 24px;
height: 24px;
border-radius: 4px;
cursor: pointer;
}
.color-swatch.active {
outline: 2px solid var(--primary);
}
</style>Регистрация интерфейса в src/index.ts:
// src/index.ts
import InterfaceComponent from './interface.vue'
export default {
id: 'color-picker',
name: 'Color Picker',
icon: 'palette',
description: 'Выбор цвета из палитры',
component: InterfaceComponent,
types: ['string'], // для каких типов полей доступен
options: [
{
field: 'presetColors',
name: 'Preset Colors',
type: 'json',
meta: {
interface: 'tags',
options: {
placeholder: '#FF5733',
},
},
},
{
field: 'placeholder',
name: 'Placeholder',
type: 'string',
meta: {
interface: 'input',
},
},
],
}
Другой частый пример — оценка звёздами (star rating):
<!-- Star Rating Interface -->
<template>
<div class="star-rating">
<span
v-for="star in maxStars"
:key="star"
class="star"
:class="{ filled: star <= (hoveredStar || value || 0) }"
@click="$emit('input', star)"
@mouseenter="hoveredStar = star"
@mouseleave="hoveredStar = null"
>★</span>
<span v-if="value" class="value-label">{{ value }}/{{ maxStars }}</span>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const props = defineProps<{
value: number | null
maxStars?: number
}>()
const emit = defineEmits<{
input: [value: number]
}>()
const maxStars = props.maxStars || 5
const hoveredStar = ref<number | null>(null)
</script> Почему кастомный интерфейс экономит время?
Готовые интерфейсы Directus покрывают 80% типовых полей, но оставшиеся 20% — самые ценные: они напрямую влияют на UX администратора. Кастомный интерфейс Directus в 3-5 раз ускоряет ввод данных по сравнению с сырым JSON-полем или отдельным скриптом. Вот сравнение:
| Критерий | Стандартный интерфейс | Кастомный интерфейс |
|---|---|---|
| Время ввода данных | 20–30 сек. на запись | 5–10 сек. |
| Ошибки пользователя | 15% записей с ошибками | <2% |
| Возможность кастомизации | Только настройки темы | Полный контроль |
| Поддержка нестандартных типов | Нет | Любые (цвет, карта, рейтинг) |
Кастомизация панели администратора Directus через кастомные интерфейсы — это способ адаптировать админку под бизнес-требования без лишних телодвижений. Мы используем TypeScript, Vue 3 Composition API и официальный CLI — никаких костылей. Гарантируем совместимость с последней стабильной версией Directus. Каждый интерфейс проходит code review и тестирование в трёх браузерах.
Что входит в работу
- Документация: README с инструкцией по установке и настройке, описание всех опций.
- Исходный код в вашем репозитории (GitHub/GitLab).
- Сборка и публикация как npm-пакета (опционально).
- Обучение администраторов: сессия 30–60 минут.
- 14 дней поддержки после деплоя: исправление багов, консультации.
Процесс работы
- Аналитика: обсуждаем UI/UX прототип, определяем типы полей, дополнительные опции.
- Проектирование: создаём спецификацию компонента на Vue 3, продумываем состояния (пусто, ошибка, загрузка).
- Разработка: пишем компонент с Composition API, настраиваем регистрацию, добавляем локализацию (i18n).
- Тестирование: проверяем в изолированном Directus-проекте, эмуляцию разных версий, тесты на корректность данных.
- Интеграция: устанавливаем на вашем сервере, настраиваем права доступа.
- Деплой: публикуем в production, документируем.
Сроки
| Тип интерфейса | Срок | Примечание |
|---|---|---|
| Простой (color picker, toggle) | 1–2 дня | Стоимость рассчитывается индивидуально |
| Средний (рейтинг с полузвёздами, слайдер) | 2–3 дня | Стоимость рассчитывается индивидуально |
| Сложный (карта, асинхронный поиск) | 3–5 дней | Стоимость рассчитывается индивидуально |
Стоимость рассчитывается индивидуально — пишите, оценим проект под ключ.
Типичные ошибки при самостоятельной разработке
- Неверная типизация: если интерфейс зарегистрирован только для
string, а поле хранитinteger, данные не сохранятся. Всегда указываем корректныйtypes. - Проблемы с реактивностью: Directus ожидает синхронный эмит
input. Асинхронные обновления могут вызвать конфликт с историями. Используем только$emit('input', value). - Игнорирование рендеринга в списках: если поле отображается в таблице, компонент должен корректно работать в режиме compact. Проверяем проп
widthи адаптируем верстку.
Свяжитесь с нами, чтобы получить консультацию по вашему проекту. Мы оценим сложность и предложим оптимальное решение. Напишите нам — и мы поможем вам заказать интерфейс Directus, идеально подходящий под ваши задачи.







