Розробка кастомних інтерфейсів 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, який ідеально підходить під ваші завдання.







