Поддержка
Начало работы

Установка UI

Подключение клиентского приложения Frame

Установка клиентской части — последовательность: подключить приватный npm-реестр, поставить зависимости, создать конфигурацию Vite и точку входа, скачать шрифт локально, прописать стили и локализацию, собрать проект.

Настройте npm

Добавьте в .npmrc проекта instance-level-адрес реестра — он отдаёт все пакеты scope @frame (в т.ч. опциональные модули @frame/permissions, @frame/notes, @frame/action-events):

.npmrc
@frame:registry=https://git.qubeek.io/api/v4/packages/npm/
//git.qubeek.io/api/v4/packages/npm/:_authToken=<ваш-токен>
Добавьте .npmrc в .gitignore — файл содержит секрет.
Токен тот же, что и для Composer (auth.json). Выдаётся службой поддержки.

Пропишите зависимости

Замените содержимое package.json:

package.json
{
  "scripts": {
    "build": "vite build",
    "dev": "vite",
    "dev:frame": "vite --config vite-frame.config.js",
    "build:frame": "vite build --config vite-frame.config.js"
  },
  "devDependencies": {
    "@frame/vue": "^0.0.13",
    "@tailwindcss/vite": "^4.1.4",
    "@types/node": "^24.1.0",
    "@vitejs/plugin-vue": "^6.0.5",
    "chokidar": "^4.0.3",
    "laravel-vite-plugin": "^2.1.0",
    "prettier": "^3.6.2",
    "tailwindcss": "^4.1.4",
    "typescript": "^5.8.3",
    "vite": "^7.1.11",
    "vue": "^3.5.13",
    "vue-tsc": "^3.0.4"
  }
}

Создайте конфигурацию Vite

vite-frame.config.js
import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
import tailwindcss from '@tailwindcss/vite'
import vue from '@vitejs/plugin-vue'

const group_chunks = [
    'vue-forms',
    'vue-table',
    'vue-charts',
    'd3',
    'tres',
    'date-fns',
    'vueuse',
    'lodash-es',
    'dicebear',
    'lottie',
    'tabler',
    'tanstack',
    'simplewebauthn',
]

export default defineConfig({
    allowedHosts: true,
    server: {
        cors: {
            origin: /https?:\/\/([A-Za-z0-9-.]+)?(localhost|\.test|\.lan)(?::\d+)?$/,
        },
    },
    plugins: [
        vue({
            template: {
                transformAssetUrls: {
                    includeAbsolute: false,
                },
            },
        }),
        tailwindcss(),
        laravel({
            input: ['resources/js/frame.ts'],
            buildDirectory: 'frame',
            refresh: true,
        }),
    ],
    build: {
        rollupOptions: {
            output: {
                manualChunks: (id) => {
                    let outputId = null

                    group_chunks.map((i) => {
                        if (id.includes(i)) {
                            outputId = i
                        }
                    })

                    if (outputId) {
                        return outputId
                    }
                },
            },
        },
    },
})

Создайте точку входа

resources/js/frame.ts
import { createApp } from 'vue'
// @ts-ignore
import { Frame, FramePlugin } from '@frame/vue'
import '../css/frame.css'

import locale from '../../lang/ru.json'

const app = createApp(Frame)

app.use(FramePlugin, {
  path: '/',
  endpoint: '/api/frame',
  appName: 'My Application',
  appLogoPath: '/images/logo.png',
  i18n: locale,
})

app.mount('#app')

Полный перечень опций FramePlugin и их PHP-эквивалентов — в разделе Конфигурация приложения.

Скачайте шрифт локально

По умолчанию Frame использует Onest. Чтобы избавиться от зависимости от Google Fonts, положите variable-версию рядом с приложением в public/fonts/onest/:

mkdir -p public/fonts/onest && cd public/fonts/onest
curl -sfL "https://fonts.gstatic.com/s/onest/v9/gNMKW3F-SZuj7xmS-HYoEoeyxMI.woff2" -o onest-cyrillic-ext.woff2
curl -sfL "https://fonts.gstatic.com/s/onest/v9/gNMKW3F-SZuj7xmb-HYoEoeyxMI.woff2" -o onest-cyrillic.woff2
curl -sfL "https://fonts.gstatic.com/s/onest/v9/gNMKW3F-SZuj7xmR-HYoEoeyxMI.woff2" -o onest-latin-ext.woff2
curl -sfL "https://fonts.gstatic.com/s/onest/v9/gNMKW3F-SZuj7xmf-HYoEoey.woff2" -o onest-latin.woff2
URL-ы выше — текущая версия (v9) variable-шрифта из Google Fonts. Актуальный список можно получить запросом CSS с современным User-Agent:
curl -A "Mozilla/5.0 ... Chrome" "https://fonts.googleapis.com/css2?family=Onest:wght@100..900&display=swap"

Добавьте стили

resources/css/frame.css
@import 'tailwindcss' source(none);
@import '../../node_modules/@frame/core/styles/theme.css';
@import '../../node_modules/@frame/vue/dist/vue.css';
@config '../../node_modules/@frame/core/dist/tailwind.config.js';

@source '../../node_modules/@frame/core';
@source '../../node_modules/@frame/vue';
@source '../../node_modules/@frame/vue-table';
@source '../../node_modules/@frame/vue-charts';
@source '../../node_modules/@frame/vue-forms';
@source '../../node_modules/@frame/vue-uploader';
@source '../js';

@font-face {
    font-family: 'Onest';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('/fonts/onest/onest-cyrillic-ext.woff2') format('woff2');
    unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

@font-face {
    font-family: 'Onest';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('/fonts/onest/onest-cyrillic.woff2') format('woff2');
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
    font-family: 'Onest';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('/fonts/onest/onest-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Onest';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('/fonts/onest/onest-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
    --font-family: 'Onest', ui-sans-serif, system-ui, sans-serif;
}

html,
body {
    font-family: var(--font-family), sans-serif;
}
@source '../js' подхватывает ваши кастомные компоненты для Tailwind. Чтобы подключить свой шрифт — положите woff2-файлы в public/fonts/<family>/ и замените блоки @font-face. Для смены бренд-цвета и тёмной темы см. Стилизация темы и Дизайн-токены.

Настройте локализацию

Скопируйте базовый файл переводов из вендора:

cp vendor/frame/frame/packages/laravel/resources/lang/ru.json lang/ru.json

При подключении модулей (frame/permissions, frame/notes, frame/action-events) слейте их переводы в объект i18n:

resources/js/frame.ts
import locale from '../../lang/ru.json'
import permissionsLocale from '../../vendor/frame/permissions/resources/lang/ru.json'

app.use(FramePlugin, {
  i18n: { ...locale, ...permissionsLocale },
  // ...
})

Соберите проект

Удалите node_modules и package-lock.json, затем переустановите зависимости и соберите:

rm -rf node_modules package-lock.json && npm install --legacy-peer-deps
npm run build:frame
Флаг --legacy-peer-deps нужен, потому что @tailwindcss/vite отстаёт от последних версий vite по peerDependencies. После выравнивания апстримом флаг можно убрать.

Кастомизация

Название, логотип, локаль и пути задаются через FramePlugin (JS) или через Frame\Core\Config\Config в сервис-провайдере (PHP). PHP имеет приоритет над JS. Подробно — в разделе Конфигурация приложения.

Что дальше