UnicoreCMS

Встраивание в интерфейс

Пункты меню, вкладки и слоты на готовых экранах

Кроме собственных страниц модуль добавляет пункты навигации и вставляет блоки в готовые экраны ядра. И то и другое объявляется в плагине слоя.

client/plugins/register.ts
import { defineClientModule } from 'unicore-api/client'
import Gallery from '../components/Gallery.vue'
import FooterLinks from '../components/FooterLinks.vue'

export default defineNuxtPlugin(() => {
  defineClientModule({
    id: 'screens',
    nav: [
      { key: 'screens', to: '/mod/screens', label: 'mod.screens.title', icon: 'bx bx-image', places: ['navbar'], order: 50 },
      { key: 'screens.tab', to: '/mod/screens/my', label: 'mod.screens.tab', places: ['cabinet.tabs'], order: 95 },
    ],
    slots: [
      { slot: 'server.page', component: Gallery, order: 10 },
      { slot: 'footer', component: FooterLinks, order: 10 },
    ],
  })
})

Компонент передаётся импортом

Строку с именем компонента ядро тоже примет, но резолвится она только для компонентов, объявленных в слое с global: true. На собранном фронте неудачная строка не даёт ни ошибки, ни предупреждения — просто пустое место. Импортируйте компонент и передавайте его самого.

Всё зарегистрированное живёт ровно столько, сколько модуль включён: ядро отдаёт фронтам список включённых модулей, и записи выключенного из навигации и слотов не попадают. Отдельно проверять это в модуле не нужно.

Места навигации

МестоГде видно
navbarВерхнее меню сайта
footerСсылки в подвале
cabinetВерхнее меню кабинета
cabinet.tabsВкладки кабинета
store.tabsВкладки магазина
players.tabsВкладки раздела «Игроки»

Поле when решает, кому пункт виден: always (по умолчанию), auth — только вошедшим, guest — только гостям. То же поле есть у слота. order задаёт порядок среди соседей: ядро занимает шаги по десяткам, так что промежуточные значения свободны.

Пункты меню из данных

Если пункты зависят не от кода, а от того, что владелец завёл в панели, вместо массива передайте функцию — ядро зовёт её каждый раз, когда собирает меню:

client/plugins/register.ts
export default defineNuxtPlugin(async () => {
  const items = useState<NavForm[]>('mod-screens-nav', () => [])

  if (!items.value.length) items.value = await load()

  defineClientModule({
    id: 'screens',
    nav: () => items.value.map((item) => ({
      key: `screens.${item.slug}`,
      to: `/mod/screens/${item.slug}`,
      label: item.title,
      places: ['navbar'],
      order: item.order,
    })),
  })
})

Два правила, без которых это не работает:

  • список кладите в useState — так он попадает в payload и на клиенте не запрашивается второй раз;
  • запрос делайте самим $fetch по useRuntimeConfig().public.apiBaseurl: плагины слоя выполняются раньше плагинов приложения, и $api в этот момент ещё не объявлен. Заголовок языка берите из LOCALE_HEADER — он экспортируется из unicore-api/client.

На SSR плагин отрабатывает на каждый запрос страницы, поэтому держите в модуле короткий кэш ответа: иначе каждый заход на сайт превращается в лишний запрос к бэкенду.

Ничего не появляется в шапке само

Пункт меню — это решение владельца, а не побочный эффект установки. В «Конструкторе форм» за это отвечает флажок «Показывать в меню сайта», выключенный по умолчанию. Делайте так же: модуль, который без спроса лезет в навигацию, снесут первым.

Слоты сайта

СлотКуда попадаетЧто получает
home.top, home.bottomГлавная, до и после новостей—
footerПодвал под ссылками—
servers.listСписок серверовservers
server.pageСтраница сервераserver
news.pageПод текстом новостиnews
user.profileПубличный профиль игрокаuser
start.pageСтраница «Начать игру»—
cabinet.indexГлавная кабинета—
store.catalogКаталог магазина—
store.productКарточка товараproduct, server
donate.indexВыбор сервера для доната—
donate.serverСтраница доната сервераserver

Слоты панели

СлотКуда попадаетЧто получает
dashboardПанель управления—
users.profileКарточка игрокаuser

Объявляются через defineAdminModule из unicore-api/admin. Там же — пункты меню панели (menu) и права на маршруты модуля (access: superuser либо список прав). Пункты всех модулей собираются в отдельную группу «Расширения» внизу меню.

admin/plugins/register.ts
import { defineAdminModule } from 'unicore-api/admin'
import DashboardCard from '../components/DashboardCard.vue'

export default defineNuxtPlugin(() => {
  defineAdminModule({
    id: 'screens',
    menu: [{ label: 'mod.screens.title', icon: 'pi pi-images', to: '/mod/screens' }],
    access: { '/mod/screens': ['mod.screens.read'] },
    slots: [{ slot: 'dashboard', component: DashboardCard, order: 10 }],
  })
})

Данные слота

Компонент получает их обычными пропсами:

components/Gallery.vue
<template>
  <div v-if="shots.length" class="panel">
    <h2>{{ $t('mod.screens.title') }}</h2>
    <img v-for="shot in shots" :key="shot.id" :src="shot.url" />
  </div>
</template>

<script setup lang="ts">
const props = defineProps<{ server?: { id: number } }>()
const { data: shots } = await useFetch(`/mod/screens?server=${props.server?.id}`)
</script>

Опечатку видно сразу

Неизвестное имя слота или места ядро сообщает в консоли при регистрации модуля. Экран не остаётся молча пустым.

Содержание