@dskripchenko/laravel-admin 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +226 -0
- package/dist/.gitkeep +0 -0
- package/dist/api/bootstrap.d.ts +38 -0
- package/dist/api/bootstrap.test.d.ts +1 -0
- package/dist/api/client.d.ts +30 -0
- package/dist/api/client.test.d.ts +1 -0
- package/dist/api/envelope.d.ts +24 -0
- package/dist/api/envelope.test.d.ts +1 -0
- package/dist/api/errors.d.ts +40 -0
- package/dist/api/errors.test.d.ts +1 -0
- package/dist/components/AdminApp.vue.d.ts +2 -0
- package/dist/components/ForbiddenPage.vue.d.ts +2 -0
- package/dist/components/HomePage.vue.d.ts +2 -0
- package/dist/components/NotFoundPage.vue.d.ts +2 -0
- package/dist/components/SettingsPage.vue.d.ts +2 -0
- package/dist/components/UnknownScreenPage.vue.d.ts +2 -0
- package/dist/components/auth/LoginForm.test.d.ts +1 -0
- package/dist/components/auth/LoginForm.vue.d.ts +17 -0
- package/dist/components/auth/LoginPage.test.d.ts +1 -0
- package/dist/components/auth/LoginPage.vue.d.ts +26 -0
- package/dist/components/auth/TwoFactorForm.test.d.ts +1 -0
- package/dist/components/auth/TwoFactorForm.vue.d.ts +8 -0
- package/dist/components/auth/index.d.ts +6 -0
- package/dist/components/createComponentRegistry.d.ts +22 -0
- package/dist/components/dashboard/BarChartWidget.vue.d.ts +18 -0
- package/dist/components/dashboard/DashboardPage.test.d.ts +1 -0
- package/dist/components/dashboard/DashboardPage.vue.d.ts +28 -0
- package/dist/components/dashboard/DonutChartWidget.vue.d.ts +13 -0
- package/dist/components/dashboard/GaugeWidget.vue.d.ts +29 -0
- package/dist/components/dashboard/HeatmapWidget.vue.d.ts +18 -0
- package/dist/components/dashboard/MarkdownWidget.vue.d.ts +8 -0
- package/dist/components/dashboard/RecentTableWidget.vue.d.ts +12 -0
- package/dist/components/dashboard/StatWidget.vue.d.ts +22 -0
- package/dist/components/dashboard/UnknownWidget.vue.d.ts +5 -0
- package/dist/components/dashboard/WidgetRenderer.vue.d.ts +10 -0
- package/dist/components/dashboard/builtin.d.ts +4 -0
- package/dist/components/dashboard/index.d.ts +16 -0
- package/dist/components/dashboard/registry.d.ts +25 -0
- package/dist/components/dashboard/registry.test.d.ts +1 -0
- package/dist/components/fields/CheckboxField.vue.d.ts +16 -0
- package/dist/components/fields/DateField.vue.d.ts +25 -0
- package/dist/components/fields/NumberField.vue.d.ts +24 -0
- package/dist/components/fields/SelectField.vue.d.ts +28 -0
- package/dist/components/fields/TextAreaField.vue.d.ts +20 -0
- package/dist/components/fields/TextField.vue.d.ts +22 -0
- package/dist/components/fields/UnknownField.vue.d.ts +6 -0
- package/dist/components/fields/fields.test.d.ts +1 -0
- package/dist/components/fields/wysiwyg/quill/QuillField.vue.d.ts +26 -0
- package/dist/components/fields/wysiwyg/quill/index.d.ts +12 -0
- package/dist/components/fields/wysiwyg/tinymce/TinymceField.vue.d.ts +31 -0
- package/dist/components/fields/wysiwyg/tinymce/index.d.ts +12 -0
- package/dist/components/gallery/FieldGalleryPage.test.d.ts +1 -0
- package/dist/components/gallery/FieldGalleryPage.vue.d.ts +2 -0
- package/dist/components/gallery/index.d.ts +1 -0
- package/dist/components/import/ImportWizardPage.test.d.ts +1 -0
- package/dist/components/import/ImportWizardPage.vue.d.ts +59 -0
- package/dist/components/import/index.d.ts +1 -0
- package/dist/components/infolist/BadgeEntry.vue.d.ts +18 -0
- package/dist/components/infolist/IconEntry.vue.d.ts +22 -0
- package/dist/components/infolist/InfolistRenderer.test.d.ts +1 -0
- package/dist/components/infolist/InfolistRenderer.vue.d.ts +11 -0
- package/dist/components/infolist/KeyValueEntry.vue.d.ts +11 -0
- package/dist/components/infolist/TextEntry.vue.d.ts +17 -0
- package/dist/components/infolist/UnknownEntry.vue.d.ts +6 -0
- package/dist/components/infolist/builtin.d.ts +4 -0
- package/dist/components/infolist/index.d.ts +13 -0
- package/dist/components/infolist/recordContext.d.ts +9 -0
- package/dist/components/infolist/registry.d.ts +19 -0
- package/dist/components/infolist/registry.test.d.ts +1 -0
- package/dist/components/layouts/ColumnsLayout.vue.d.ts +13 -0
- package/dist/components/layouts/RowsLayout.vue.d.ts +10 -0
- package/dist/components/layouts/SectionLayout.vue.d.ts +11 -0
- package/dist/components/layouts/TabsLayout.vue.d.ts +22 -0
- package/dist/components/notifications/NotificationsDrawer.test.d.ts +1 -0
- package/dist/components/notifications/NotificationsDrawer.vue.d.ts +13 -0
- package/dist/components/notifications/index.d.ts +1 -0
- package/dist/components/profile/ProfilePage.test.d.ts +1 -0
- package/dist/components/profile/ProfilePage.vue.d.ts +50 -0
- package/dist/components/profile/index.d.ts +1 -0
- package/dist/components/render/FieldRenderer.test.d.ts +1 -0
- package/dist/components/render/FieldRenderer.vue.d.ts +9 -0
- package/dist/components/render/LayoutRenderer.test.d.ts +1 -0
- package/dist/components/render/LayoutRenderer.vue.d.ts +10 -0
- package/dist/components/render/builtin.d.ts +9 -0
- package/dist/components/render/formState.d.ts +36 -0
- package/dist/components/render/formState.test.d.ts +1 -0
- package/dist/components/render/index.d.ts +23 -0
- package/dist/components/render/registry.d.ts +35 -0
- package/dist/components/render/registry.test.d.ts +1 -0
- package/dist/components/resource/ResourceFormPage.test.d.ts +1 -0
- package/dist/components/resource/ResourceFormPage.vue.d.ts +13 -0
- package/dist/components/resource/ResourceIndexPage.test.d.ts +1 -0
- package/dist/components/resource/ResourceIndexPage.vue.d.ts +44 -0
- package/dist/components/resource/ResourceViewPage.test.d.ts +1 -0
- package/dist/components/resource/ResourceViewPage.vue.d.ts +13 -0
- package/dist/components/resource/index.d.ts +6 -0
- package/dist/components/shell/AdminShell.vue.d.ts +35 -0
- package/dist/components/shell/AdminSidebar.test.d.ts +1 -0
- package/dist/components/shell/AdminSidebar.vue.d.ts +27 -0
- package/dist/components/shell/AdminTopBar.test.d.ts +1 -0
- package/dist/components/shell/AdminTopBar.vue.d.ts +33 -0
- package/dist/components/shell/index.d.ts +18 -0
- package/dist/components/shell/widgets/LocaleSwitcher.test.d.ts +1 -0
- package/dist/components/shell/widgets/LocaleSwitcher.vue.d.ts +2 -0
- package/dist/components/shell/widgets/NotificationBell.vue.d.ts +2 -0
- package/dist/components/shell/widgets/ThemeToggle.test.d.ts +1 -0
- package/dist/components/shell/widgets/ThemeToggle.vue.d.ts +2 -0
- package/dist/components/shell/widgets/UserMenu.test.d.ts +1 -0
- package/dist/components/shell/widgets/UserMenu.vue.d.ts +2 -0
- package/dist/createAdminApp.d.ts +85 -0
- package/dist/createAdminApp.test.d.ts +1 -0
- package/dist/formState-DGNcH1XQ.js +40 -0
- package/dist/formState-DGNcH1XQ.js.map +1 -0
- package/dist/formState-GlJBphEn.cjs +2 -0
- package/dist/formState-GlJBphEn.cjs.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.mjs +4345 -0
- package/dist/index.mjs.map +1 -0
- package/dist/quill.cjs +2 -0
- package/dist/quill.cjs.map +1 -0
- package/dist/quill.mjs +71 -0
- package/dist/quill.mjs.map +1 -0
- package/dist/router/builder.d.ts +52 -0
- package/dist/router/builder.test.d.ts +1 -0
- package/dist/router/guards.d.ts +56 -0
- package/dist/router/guards.test.d.ts +1 -0
- package/dist/router/index.d.ts +63 -0
- package/dist/router/index.test.d.ts +1 -0
- package/dist/stores/auth.d.ts +142 -0
- package/dist/stores/auth.test.d.ts +1 -0
- package/dist/stores/index.d.ts +21 -0
- package/dist/stores/locale.d.ts +29 -0
- package/dist/stores/locale.test.d.ts +1 -0
- package/dist/stores/manifest.d.ts +515 -0
- package/dist/stores/manifest.test.d.ts +1 -0
- package/dist/stores/menu.d.ts +215 -0
- package/dist/stores/menu.test.d.ts +1 -0
- package/dist/stores/notifications.d.ts +137 -0
- package/dist/stores/notifications.test.d.ts +1 -0
- package/dist/stores/registry.d.ts +16 -0
- package/dist/stores/registry.test.d.ts +1 -0
- package/dist/stores/resourceForm.d.ts +91 -0
- package/dist/stores/resourceForm.test.d.ts +1 -0
- package/dist/stores/resourceIndex.d.ts +149 -0
- package/dist/stores/resourceIndex.test.d.ts +1 -0
- package/dist/stores/theme.d.ts +29 -0
- package/dist/stores/theme.test.d.ts +1 -0
- package/dist/style.css +1 -0
- package/dist/tinymce.cjs +2 -0
- package/dist/tinymce.cjs.map +1 -0
- package/dist/tinymce.mjs +80 -0
- package/dist/tinymce.mjs.map +1 -0
- package/dist/types/bootstrap.d.ts +50 -0
- package/package.json +162 -0
- package/resources/fonts/InterDisplay-Bold.woff2 +0 -0
- package/resources/fonts/InterDisplay-ExtraBold.woff2 +0 -0
- package/resources/fonts/InterDisplay-SemiBold.woff2 +0 -0
- package/resources/fonts/InterVariable-Italic.woff2 +0 -0
- package/resources/fonts/InterVariable.woff2 +0 -0
- package/resources/fonts/fonts.css +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Denis Skripchenko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# dskripchenko/laravel-admin
|
|
2
|
+
|
|
3
|
+
Конструктор админок для Laravel: Resource-first CRUD, Vue 3 SPA, JSON-API транспорт. Подключается в любой существующий Laravel-проект без вмешательства в его routes/auth.
|
|
4
|
+
|
|
5
|
+
> **Статус:** in development. Архитектура зафиксирована, идёт реализация. См. `docs/ARCHITECTURE.md`.
|
|
6
|
+
|
|
7
|
+
## Tldr
|
|
8
|
+
|
|
9
|
+
```php
|
|
10
|
+
class UserResource extends Resource
|
|
11
|
+
{
|
|
12
|
+
public static string $model = \App\Models\User::class;
|
|
13
|
+
public static string $icon = 'user';
|
|
14
|
+
|
|
15
|
+
public function fields(): array
|
|
16
|
+
{
|
|
17
|
+
return [
|
|
18
|
+
Field\Input::make('name')->required(),
|
|
19
|
+
Field\Input::make('email')->type('email')->required()->unique(),
|
|
20
|
+
Field\Switch::make('is_active'),
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public function columns(): array
|
|
25
|
+
{
|
|
26
|
+
return [
|
|
27
|
+
TC::make('id')->sort(),
|
|
28
|
+
TC::make('name')->sort()->search(),
|
|
29
|
+
TC::make('email')->copyable(),
|
|
30
|
+
TC::make('is_active')->as('badge'),
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```php
|
|
37
|
+
// AppServiceProvider
|
|
38
|
+
Admin::resources([UserResource::class]);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Готово: SPA с list/create/edit/view/audit/permissions.
|
|
42
|
+
|
|
43
|
+
## Требования
|
|
44
|
+
|
|
45
|
+
- PHP `^8.5`
|
|
46
|
+
- Laravel `^12`
|
|
47
|
+
- Redis или Memcached (для tag-aware кэша переводов; иначе soft-fallback)
|
|
48
|
+
- Vue 3.4+, TypeScript, Vite (для frontend-сборки)
|
|
49
|
+
|
|
50
|
+
## Установка
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
composer require dskripchenko/laravel-admin
|
|
54
|
+
php artisan admin:install
|
|
55
|
+
php artisan migrate
|
|
56
|
+
php artisan admin:user "Admin" admin@example.com secret
|
|
57
|
+
npm install
|
|
58
|
+
npm run admin:build
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
После этого админка доступна на `/admin`.
|
|
62
|
+
|
|
63
|
+
## Frontend SPA (`@dskripchenko/laravel-admin` npm-пакет)
|
|
64
|
+
|
|
65
|
+
Для host-проектов которые хотят встроить SPA в свой Vite-bundle вместо Blade-shell'а либо построить кастомный admin-фронт поверх готовых блоков.
|
|
66
|
+
|
|
67
|
+
### Установка
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm install @dskripchenko/laravel-admin @dskripchenko/ui vue@^3.4 vue-router@^4.3 pinia axios
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Минимальный entry
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
// resources/admin-spa/main.ts
|
|
77
|
+
import { createApp } from 'vue'
|
|
78
|
+
import { createPinia } from 'pinia'
|
|
79
|
+
|
|
80
|
+
// (1) UI-кит: токены + темы + reset + global + Uid*-стили
|
|
81
|
+
import '@dskripchenko/ui/styles/all.css'
|
|
82
|
+
// (2) admin-каркас (impersonation banner, polling-dot, page utilities)
|
|
83
|
+
import '@dskripchenko/laravel-admin/style.css'
|
|
84
|
+
|
|
85
|
+
import {
|
|
86
|
+
createAdminClient,
|
|
87
|
+
setAdminClient,
|
|
88
|
+
loadBootstrap,
|
|
89
|
+
createAdminRouter,
|
|
90
|
+
registerBuiltinComponents,
|
|
91
|
+
registerBuiltinInfolistEntries,
|
|
92
|
+
registerBuiltinWidgets,
|
|
93
|
+
AdminShell,
|
|
94
|
+
ResourceIndexPage,
|
|
95
|
+
ResourceFormPage,
|
|
96
|
+
ResourceViewPage,
|
|
97
|
+
DashboardPage,
|
|
98
|
+
} from '@dskripchenko/laravel-admin'
|
|
99
|
+
|
|
100
|
+
// 1. HTTP-клиент с envelope/CSRF/error handling
|
|
101
|
+
const client = createAdminClient({
|
|
102
|
+
baseURL: '/api/admin',
|
|
103
|
+
onUnauthenticated: () => router.push({ name: 'admin.login' }),
|
|
104
|
+
})
|
|
105
|
+
setAdminClient(client)
|
|
106
|
+
|
|
107
|
+
// 2. Bootstrap (inline через <script> либо xhr через /system/bootstrap)
|
|
108
|
+
const bootstrap = await loadBootstrap({ client })
|
|
109
|
+
|
|
110
|
+
// 3. Pinia + hydrate stores
|
|
111
|
+
const pinia = createPinia()
|
|
112
|
+
const app = createApp(AdminShell)
|
|
113
|
+
app.use(pinia)
|
|
114
|
+
|
|
115
|
+
// 4. Регистрация builtin-компонентов в JSON-renderer'ы
|
|
116
|
+
registerBuiltinComponents() // Field/Layout (text/textarea/number/select/...)
|
|
117
|
+
registerBuiltinInfolistEntries() // Read-only display (text/badge/icon/keyvalue)
|
|
118
|
+
registerBuiltinWidgets() // Dashboard widgets (stat/charts/heatmap/gauge)
|
|
119
|
+
|
|
120
|
+
// 5. Router с динамическими роутами из manifest'а
|
|
121
|
+
const router = createAdminRouter({
|
|
122
|
+
base: '/admin',
|
|
123
|
+
components: {
|
|
124
|
+
login: () => import('./pages/Login.vue'),
|
|
125
|
+
home: () => import('./pages/Home.vue'),
|
|
126
|
+
forbidden: () => import('./pages/403.vue'),
|
|
127
|
+
notFound: () => import('./pages/404.vue'),
|
|
128
|
+
resourceIndex: ResourceIndexPage,
|
|
129
|
+
resourceCreate: ResourceFormPage,
|
|
130
|
+
resourceEdit: ResourceFormPage,
|
|
131
|
+
screen: () => import('./pages/Screen.vue'),
|
|
132
|
+
settings: () => import('./pages/Settings.vue'),
|
|
133
|
+
dashboard: DashboardPage,
|
|
134
|
+
},
|
|
135
|
+
})
|
|
136
|
+
app.use(router)
|
|
137
|
+
app.mount('#admin')
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Готовые компоненты-страницы
|
|
141
|
+
|
|
142
|
+
- `LoginPage` + `LoginForm` + `TwoFactorForm` — auth + TOTP/recovery
|
|
143
|
+
- `ResourceIndexPage` — список с filter-bar / bulk toolbar / pagination
|
|
144
|
+
- `ResourceFormPage` — create/edit unified с sticky save-bar
|
|
145
|
+
- `ResourceViewPage` — read-only display через Infolist
|
|
146
|
+
- `DashboardPage` — 12-col widget grid
|
|
147
|
+
- `ProfilePage` — sidebar nav + cards
|
|
148
|
+
- `ImportWizardPage` — 4-step wizard
|
|
149
|
+
- `NotificationsDrawer` — UidDrawer right с tabs
|
|
150
|
+
- `FieldGalleryPage` — каталог field-типов (docs/playground)
|
|
151
|
+
|
|
152
|
+
### Расширение через registry
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { registerField, registerWidget, registerInfolistEntry } from '@dskripchenko/laravel-admin'
|
|
156
|
+
import MyCustomField from './fields/MyCustomField.vue'
|
|
157
|
+
|
|
158
|
+
registerField('my-custom', MyCustomField)
|
|
159
|
+
// теперь manifest узел { type: 'my-custom', name: 'x', ... } рендерится через MyCustomField
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Шрифты (опционально)
|
|
163
|
+
|
|
164
|
+
UID design system предполагает Inter Variable + Inter Display. Library не bundle'ит шрифты в style.css (Vite lib-mode инлайнит base64 → 1.4 MB). Варианты:
|
|
165
|
+
|
|
166
|
+
- `npm i @fontsource-variable/inter @fontsource/inter-display` + `import` (рекомендуется)
|
|
167
|
+
- Google Fonts CDN
|
|
168
|
+
- Self-hosted — копировать `node_modules/@dskripchenko/laravel-admin/resources/fonts/*.woff2` в `public/fonts/` + подключить `fonts.css`
|
|
169
|
+
|
|
170
|
+
### Скрипты разработки
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
npm run lint # eslint flat config + vue-eslint-parser
|
|
174
|
+
npm run typecheck # vue-tsc --noEmit
|
|
175
|
+
npm test # vitest (jsdom)
|
|
176
|
+
npm run build # vite build + vue-tsc --emitDeclarationOnly
|
|
177
|
+
npm run build:analyze # с rollup-plugin-visualizer → dist/stats.html
|
|
178
|
+
npm run size # size-limit budgets (ESM/CJS gzipped + CSS)
|
|
179
|
+
npm run preflight # lint + typecheck + test + build (CI gate)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Документация
|
|
183
|
+
|
|
184
|
+
- [ARCHITECTURE.md](docs/ARCHITECTURE.md) — архитектура и решения.
|
|
185
|
+
- [docs/sister-packs/](docs/sister-packs/) — спецификации опциональных расширений.
|
|
186
|
+
- [docs/design_handoff_laravel_admin/](docs/design_handoff_laravel_admin/) — UID design handoff (эталон вёрстки SPA).
|
|
187
|
+
|
|
188
|
+
## Sister-packs
|
|
189
|
+
|
|
190
|
+
| Пакет | Назначение |
|
|
191
|
+
|---|---|
|
|
192
|
+
| `dskripchenko/laravel-admin-starter` | Готовые системные Resource'ы |
|
|
193
|
+
| `dskripchenko/laravel-admin-tinymce` / `*-quill` | Альтернативные WYSIWYG |
|
|
194
|
+
| `dskripchenko/laravel-admin-search` | Глобальный поиск |
|
|
195
|
+
| `dskripchenko/laravel-admin-media` | Медиа-библиотека |
|
|
196
|
+
| `dskripchenko/laravel-admin-health` | Health-checks |
|
|
197
|
+
| `dskripchenko/laravel-admin-pulse` | Лёгкая телеметрия |
|
|
198
|
+
| `dskripchenko/laravel-admin-jobs` | Failed jobs viewer |
|
|
199
|
+
|
|
200
|
+
## Структура репозитория (dev)
|
|
201
|
+
|
|
202
|
+
На время разработки до первого релиза проект ведётся как **монорепо**:
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
laravel-admin/
|
|
206
|
+
├── src/ # основной пакет dskripchenko/laravel-admin
|
|
207
|
+
├── resources/ts/ # SPA-бандл @dskripchenko/laravel-admin
|
|
208
|
+
├── packages/ # sister-packs, локально
|
|
209
|
+
│ ├── starter/
|
|
210
|
+
│ ├── tinymce/
|
|
211
|
+
│ ├── quill/
|
|
212
|
+
│ ├── search/
|
|
213
|
+
│ ├── media/
|
|
214
|
+
│ ├── health/
|
|
215
|
+
│ ├── pulse/
|
|
216
|
+
│ └── jobs/
|
|
217
|
+
└── docs/
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
- Composer: корневой `composer.json` содержит `repositories: [{ type: path, url: packages/* }]` — sister-packs резолвятся локально через симлинки. Это позволяет менять core и sister-packs одновременно без публикации dev-версий.
|
|
221
|
+
- NPM: workspaces для `packages/tinymce` и `packages/quill` (только им нужны npm-зависимости). `npm install` из корня устанавливает зависимости всем сразу.
|
|
222
|
+
- **Перед первым стабильным релизом** sister-packs выносятся в отдельные репозитории на github.com/dskripchenko и публикуются на packagist/npm независимо. На этот момент `repositories` в корневом `composer.json` удаляются, sister-packs ставятся обычным `composer require`.
|
|
223
|
+
|
|
224
|
+
## License
|
|
225
|
+
|
|
226
|
+
MIT. См. [LICENSE](LICENSE).
|
package/dist/.gitkeep
ADDED
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Загрузка bootstrap-payload'а в SPA.
|
|
3
|
+
*
|
|
4
|
+
* Поддерживает обе стратегии:
|
|
5
|
+
* - 'inline' — читает window.__ADMIN_BOOTSTRAP__ (инжект через
|
|
6
|
+
* shell.blade при strategy=inline).
|
|
7
|
+
* - 'xhr' — fetch'ит /api/admin/system/bootstrap.
|
|
8
|
+
*
|
|
9
|
+
* Если оба способа не дали результата — throw'ит. SPA должна это поймать
|
|
10
|
+
* и показать full-screen error.
|
|
11
|
+
*/
|
|
12
|
+
import type { AdminBootstrap } from '../types/bootstrap';
|
|
13
|
+
import type { AdminClient } from './client';
|
|
14
|
+
export interface LoadBootstrapOptions {
|
|
15
|
+
/** Если задан client — fallback на xhr через него. */
|
|
16
|
+
client?: AdminClient;
|
|
17
|
+
/** Override URL для xhr. Default: '/system/bootstrap'. */
|
|
18
|
+
xhrUrl?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Возвращает bootstrap или null если не загрузился.
|
|
22
|
+
*
|
|
23
|
+
* Порядок:
|
|
24
|
+
* 1. window.__ADMIN_BOOTSTRAP__ (inline-strategy).
|
|
25
|
+
* 2. xhr fetch если передан client.
|
|
26
|
+
* 3. null — caller решает что делать (показать error-screen).
|
|
27
|
+
*/
|
|
28
|
+
export declare function loadBootstrap(opts?: LoadBootstrapOptions): Promise<AdminBootstrap | null>;
|
|
29
|
+
/**
|
|
30
|
+
* Прочитать bootstrap из window — только в браузерном контексте.
|
|
31
|
+
*/
|
|
32
|
+
export declare function readInlineBootstrap(): AdminBootstrap | null;
|
|
33
|
+
/**
|
|
34
|
+
* Прочитать CSRF-token из meta-tag (Blade-injection через `csrf_token()`).
|
|
35
|
+
*
|
|
36
|
+
* Используется как fallback если bootstrap.csrf отсутствует.
|
|
37
|
+
*/
|
|
38
|
+
export declare function readCsrfFromMeta(): string | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Axios-клиент для admin API.
|
|
3
|
+
*
|
|
4
|
+
* Особенности:
|
|
5
|
+
* - baseURL берётся из bootstrap.apiUrl (либо передаётся явно).
|
|
6
|
+
* - X-XSRF-TOKEN добавляется автоматически из cookie (Laravel Sanctum/web).
|
|
7
|
+
* - X-CSRF-TOKEN — fallback из meta[name=csrf-token] (Blade-injection).
|
|
8
|
+
* - X-Admin-Locale выставляется при наличии текущей локали.
|
|
9
|
+
* - Response interceptor разворачивает envelope и бросает ApiError.
|
|
10
|
+
* - 401 → onUnauthenticated callback (редирект на login на стороне consumer'а).
|
|
11
|
+
*/
|
|
12
|
+
import { type AxiosInstance, type AxiosRequestConfig } from 'axios';
|
|
13
|
+
export interface ClientOptions {
|
|
14
|
+
baseURL: string;
|
|
15
|
+
csrfToken?: string;
|
|
16
|
+
locale?: string;
|
|
17
|
+
/** Вызывается при 401. Обычно — push на /admin/login. */
|
|
18
|
+
onUnauthenticated?: () => void;
|
|
19
|
+
}
|
|
20
|
+
export interface AdminClient {
|
|
21
|
+
/** Низкоуровневый axios — для специфичных случаев. */
|
|
22
|
+
raw: AxiosInstance;
|
|
23
|
+
get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T>;
|
|
24
|
+
post<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T>;
|
|
25
|
+
put<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T>;
|
|
26
|
+
patch<T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T>;
|
|
27
|
+
delete<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<T>;
|
|
28
|
+
setLocale(locale: string): void;
|
|
29
|
+
}
|
|
30
|
+
export declare function createAdminClient(opts: ClientOptions): AdminClient;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Контракт ответов laravel-api: каждое тело — `{success, payload}`.
|
|
3
|
+
*
|
|
4
|
+
* Success: `{success: true, payload: {...}}`
|
|
5
|
+
* Error: `{success: false, payload: {errorKey, message, ...}}`
|
|
6
|
+
*
|
|
7
|
+
* Helper'ы здесь — для type-narrowing'а в потребителях.
|
|
8
|
+
*/
|
|
9
|
+
export interface SuccessEnvelope<T = unknown> {
|
|
10
|
+
success: true;
|
|
11
|
+
payload: T;
|
|
12
|
+
}
|
|
13
|
+
export interface ErrorEnvelope {
|
|
14
|
+
success: false;
|
|
15
|
+
payload: {
|
|
16
|
+
errorKey: string;
|
|
17
|
+
message: string;
|
|
18
|
+
messages?: Record<string, string[]>;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export type ApiEnvelope<T = unknown> = SuccessEnvelope<T> | ErrorEnvelope;
|
|
23
|
+
export declare function isSuccess<T>(env: ApiEnvelope<T>): env is SuccessEnvelope<T>;
|
|
24
|
+
export declare function isError(env: ApiEnvelope): env is ErrorEnvelope;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Кастомные Error-классы для admin API.
|
|
3
|
+
*
|
|
4
|
+
* Все API-ошибки бросаются как ApiError или его подклассы. Потребители
|
|
5
|
+
* могут делать `instanceof ValidationError` для специфичной обработки.
|
|
6
|
+
*/
|
|
7
|
+
import type { ErrorEnvelope } from './envelope';
|
|
8
|
+
export declare class ApiError extends Error {
|
|
9
|
+
readonly status: number;
|
|
10
|
+
readonly errorKey: string;
|
|
11
|
+
readonly payload: ErrorEnvelope['payload'];
|
|
12
|
+
constructor(status: number, payload: ErrorEnvelope['payload']);
|
|
13
|
+
}
|
|
14
|
+
export declare class UnauthenticatedError extends ApiError {
|
|
15
|
+
constructor(payload: ErrorEnvelope['payload']);
|
|
16
|
+
}
|
|
17
|
+
export declare class ForbiddenError extends ApiError {
|
|
18
|
+
constructor(payload: ErrorEnvelope['payload']);
|
|
19
|
+
}
|
|
20
|
+
export declare class NotFoundError extends ApiError {
|
|
21
|
+
constructor(payload: ErrorEnvelope['payload']);
|
|
22
|
+
}
|
|
23
|
+
export declare class ValidationError extends ApiError {
|
|
24
|
+
/** Field-keyed map of error messages. */
|
|
25
|
+
readonly fields: Record<string, string[]>;
|
|
26
|
+
constructor(payload: ErrorEnvelope['payload']);
|
|
27
|
+
/** Первое сообщение из field'а — удобно для toast. */
|
|
28
|
+
firstFieldMessage(): string | null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Network-failure (не дошли до сервера). Отдельный класс чтобы UI мог
|
|
32
|
+
* показать «Нет соединения» вместо «500 Server Error».
|
|
33
|
+
*/
|
|
34
|
+
export declare class NetworkError extends Error {
|
|
35
|
+
constructor(message?: string);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Превращает HTTP-status + envelope в правильный подкласс ApiError.
|
|
39
|
+
*/
|
|
40
|
+
export declare function toApiError(status: number, payload: ErrorEnvelope['payload']): ApiError;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
/** URL «Забыли пароль?» — если задан, показывается link справа от remember. */
|
|
3
|
+
forgotUrl?: string | null;
|
|
4
|
+
/** Текст SSO-ссылки или null чтобы скрыть. */
|
|
5
|
+
ssoLinkLabel?: string | null;
|
|
6
|
+
ssoUrl?: string | null;
|
|
7
|
+
}
|
|
8
|
+
declare const _default: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
9
|
+
success: (result: "authenticated" | "two_factor_required") => any;
|
|
10
|
+
}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
|
|
11
|
+
onSuccess?: ((result: "authenticated" | "two_factor_required") => any) | undefined;
|
|
12
|
+
}>, {
|
|
13
|
+
forgotUrl: string | null;
|
|
14
|
+
ssoLinkLabel: string | null;
|
|
15
|
+
ssoUrl: string | null;
|
|
16
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
17
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
brandName?: string;
|
|
3
|
+
brandMark?: string;
|
|
4
|
+
brandLogo?: string | null;
|
|
5
|
+
homeRouteName?: string;
|
|
6
|
+
redirectQueryKey?: string;
|
|
7
|
+
/** URL «Забыли пароль?» — пробрасывается в LoginForm. */
|
|
8
|
+
forgotUrl?: string | null;
|
|
9
|
+
/** SSO-link (label + url) — пробрасывается в LoginForm. */
|
|
10
|
+
ssoLinkLabel?: string | null;
|
|
11
|
+
ssoUrl?: string | null;
|
|
12
|
+
/** Показывать ли theme/locale toggle'ы в углу. */
|
|
13
|
+
showCornerActions?: boolean;
|
|
14
|
+
}
|
|
15
|
+
declare const _default: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
16
|
+
brandName: string;
|
|
17
|
+
brandMark: string;
|
|
18
|
+
forgotUrl: string | null;
|
|
19
|
+
ssoLinkLabel: string | null;
|
|
20
|
+
ssoUrl: string | null;
|
|
21
|
+
brandLogo: string | null;
|
|
22
|
+
homeRouteName: string;
|
|
23
|
+
redirectQueryKey: string;
|
|
24
|
+
showCornerActions: boolean;
|
|
25
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
26
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
2
|
+
success: () => any;
|
|
3
|
+
cancel: () => any;
|
|
4
|
+
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
5
|
+
onSuccess?: (() => any) | undefined;
|
|
6
|
+
onCancel?: (() => any) | undefined;
|
|
7
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
8
|
+
export default _default;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic factory для component-registry'ов (fields, layouts, widgets,
|
|
3
|
+
* infolist entries и т.п.).
|
|
4
|
+
*
|
|
5
|
+
* Все component-registry в admin'е по сути одинаковы: keyed Map<string, Component>
|
|
6
|
+
* + register/get/has/list/clear/registerBundle. Этот factory вытаскивает паттерн
|
|
7
|
+
* один раз; конкретные модули просто переименовывают экспорты.
|
|
8
|
+
*
|
|
9
|
+
* const reg = createComponentRegistry<Component>()
|
|
10
|
+
* export const registerWidget = reg.register
|
|
11
|
+
* export const getWidget = reg.get
|
|
12
|
+
* // ...
|
|
13
|
+
*/
|
|
14
|
+
export interface ComponentRegistry<T> {
|
|
15
|
+
register(type: string, value: T): void;
|
|
16
|
+
get(type: string): T | null;
|
|
17
|
+
has(type: string): boolean;
|
|
18
|
+
list(): string[];
|
|
19
|
+
clear(): void;
|
|
20
|
+
registerBundle(bundle: Record<string, T>): void;
|
|
21
|
+
}
|
|
22
|
+
export declare function createComponentRegistry<T>(): ComponentRegistry<T>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface Datum {
|
|
2
|
+
label: string;
|
|
3
|
+
value: number;
|
|
4
|
+
}
|
|
5
|
+
interface Props {
|
|
6
|
+
title?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
data: Datum[];
|
|
9
|
+
accent?: string;
|
|
10
|
+
height?: number;
|
|
11
|
+
}
|
|
12
|
+
declare const _default: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
13
|
+
title: string;
|
|
14
|
+
description: string;
|
|
15
|
+
height: number;
|
|
16
|
+
accent: string;
|
|
17
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type WidgetNode } from './WidgetRenderer.vue';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Slug dashboard'а в manifest.dashboards. */
|
|
4
|
+
slug?: string;
|
|
5
|
+
/** Прямой override widget'ов (если slug не задан или не нашёлся). */
|
|
6
|
+
widgets?: WidgetNode[];
|
|
7
|
+
/** Заголовок страницы. */
|
|
8
|
+
title?: string;
|
|
9
|
+
/** Подзаголовок (description). */
|
|
10
|
+
subtitle?: string;
|
|
11
|
+
}
|
|
12
|
+
declare var __VLS_1: {};
|
|
13
|
+
type __VLS_Slots = {} & {
|
|
14
|
+
actions?: (props: typeof __VLS_1) => any;
|
|
15
|
+
};
|
|
16
|
+
declare const __VLS_component: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
17
|
+
title: string;
|
|
18
|
+
slug: string;
|
|
19
|
+
subtitle: string;
|
|
20
|
+
widgets: WidgetNode[];
|
|
21
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
22
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
23
|
+
export default _default;
|
|
24
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
25
|
+
new (): {
|
|
26
|
+
$slots: S;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface Slice {
|
|
2
|
+
label: string;
|
|
3
|
+
value: number;
|
|
4
|
+
color?: string;
|
|
5
|
+
}
|
|
6
|
+
interface Props {
|
|
7
|
+
title?: string;
|
|
8
|
+
data: Slice[];
|
|
9
|
+
}
|
|
10
|
+
declare const _default: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
11
|
+
title: string;
|
|
12
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { GaugeRange } from '@dskripchenko/ui';
|
|
2
|
+
type SemanticTone = 'neutral' | 'positive' | 'warning' | 'negative';
|
|
3
|
+
interface Props {
|
|
4
|
+
title?: string;
|
|
5
|
+
value?: number;
|
|
6
|
+
min?: number;
|
|
7
|
+
max?: number;
|
|
8
|
+
size?: number;
|
|
9
|
+
ranges?: GaugeRange[];
|
|
10
|
+
tone?: SemanticTone;
|
|
11
|
+
color?: string;
|
|
12
|
+
label?: string;
|
|
13
|
+
suffix?: string;
|
|
14
|
+
precision?: number;
|
|
15
|
+
}
|
|
16
|
+
declare const _default: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
17
|
+
value: number;
|
|
18
|
+
label: string;
|
|
19
|
+
title: string;
|
|
20
|
+
color: string;
|
|
21
|
+
size: number;
|
|
22
|
+
suffix: string;
|
|
23
|
+
precision: number;
|
|
24
|
+
tone: SemanticTone;
|
|
25
|
+
min: number;
|
|
26
|
+
max: number;
|
|
27
|
+
ranges: GaugeRange[];
|
|
28
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
29
|
+
export default _default;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface HeatmapPoint {
|
|
2
|
+
date: string;
|
|
3
|
+
value: number;
|
|
4
|
+
}
|
|
5
|
+
interface Props {
|
|
6
|
+
title?: string;
|
|
7
|
+
data: HeatmapPoint[];
|
|
8
|
+
levels?: number;
|
|
9
|
+
color?: string;
|
|
10
|
+
gap?: number;
|
|
11
|
+
}
|
|
12
|
+
declare const _default: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
13
|
+
title: string;
|
|
14
|
+
color: string;
|
|
15
|
+
levels: number;
|
|
16
|
+
gap: number;
|
|
17
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
|
+
export default _default;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
title?: string;
|
|
3
|
+
content: string;
|
|
4
|
+
}
|
|
5
|
+
declare const _default: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
6
|
+
title: string;
|
|
7
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
8
|
+
export default _default;
|