@nan0web/ui 1.8.0 → 1.10.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/README.md +29 -10
- package/package.json +18 -22
- package/src/Model/index.js +32 -3
- package/src/core/Form/Form.js +8 -7
- package/src/core/Form/Message.js +1 -1
- package/src/core/GeneratorRunner.js +10 -0
- package/src/core/Intent.js +21 -5
- package/src/core/IntentErrorModel.js +6 -1
- package/src/core/Stream.js +16 -5
- package/src/core/index.js +1 -1
- package/src/domain/FooterModel.js +57 -0
- package/src/domain/HeaderModel.js +50 -0
- package/src/domain/HeroModel.js +48 -0
- package/src/domain/Navigation.js +11 -10
- package/src/domain/SandboxModel.js +66 -115
- package/src/domain/ShowcaseAppModel.js +133 -50
- package/src/domain/components/AccordionModel.js +38 -0
- package/src/domain/components/AutocompleteModel.js +11 -21
- package/src/domain/components/BannerModel.js +37 -0
- package/src/domain/components/BreadcrumbModel.js +11 -9
- package/src/domain/components/ButtonModel.js +31 -58
- package/src/domain/components/CommentModel.js +44 -0
- package/src/domain/components/ConfirmModel.js +26 -33
- package/src/domain/components/EmptyStateModel.js +45 -0
- package/src/domain/components/FAQModel.js +32 -0
- package/src/domain/components/FooterConfigModel.js +26 -0
- package/src/domain/components/FooterVisibilityModel.js +48 -0
- package/src/domain/components/GalleryModel.js +36 -0
- package/src/domain/components/HeaderConfigModel.js +26 -0
- package/src/domain/components/HeaderVisibilityModel.js +54 -0
- package/src/domain/components/InputModel.js +21 -41
- package/src/domain/components/PriceModel.js +30 -0
- package/src/domain/components/PricingModel.js +39 -0
- package/src/domain/components/PricingSectionModel.js +32 -0
- package/src/domain/components/ProfileDropdownModel.js +45 -0
- package/src/domain/components/SelectModel.js +11 -21
- package/src/domain/components/SpinnerModel.js +11 -26
- package/src/domain/components/StatsItemModel.js +38 -0
- package/src/domain/components/StatsModel.js +32 -0
- package/src/domain/components/TableModel.js +11 -24
- package/src/domain/components/TabsModel.js +30 -0
- package/src/domain/components/TestimonialModel.js +24 -0
- package/src/domain/components/TimelineItemModel.js +38 -0
- package/src/domain/components/TimelineModel.js +32 -0
- package/src/domain/components/ToastModel.js +24 -51
- package/src/domain/components/TreeModel.js +10 -26
- package/src/domain/components/index.js +34 -0
- package/src/domain/index.js +24 -0
- package/src/index.js +2 -0
- package/src/testing/GalleryGenerator.js +85 -0
- package/src/testing/LogicInspector.js +55 -0
- package/src/testing/SnapshotInspector.js +84 -0
- package/src/testing/VisualAdapter.js +41 -0
- package/src/testing/index.js +3 -0
- package/types/Model/index.d.ts +62 -4
- package/types/core/Form/Form.d.ts +2 -2
- package/types/core/GeneratorRunner.d.ts +4 -0
- package/types/core/Intent.d.ts +31 -3
- package/types/core/IntentErrorModel.d.ts +4 -0
- package/types/core/index.d.ts +1 -1
- package/types/domain/FooterModel.d.ts +52 -0
- package/types/domain/HeaderModel.d.ts +45 -0
- package/types/domain/HeroModel.d.ts +43 -0
- package/types/domain/Navigation.d.ts +10 -9
- package/types/domain/SandboxModel.d.ts +16 -40
- package/types/domain/ShowcaseAppModel.d.ts +26 -54
- package/types/domain/components/AccordionModel.d.ts +33 -0
- package/types/domain/components/AutocompleteModel.d.ts +10 -29
- package/types/domain/components/BannerModel.d.ts +32 -0
- package/types/domain/components/BreadcrumbModel.d.ts +13 -6
- package/types/domain/components/ButtonModel.d.ts +18 -54
- package/types/domain/components/CommentModel.d.ts +39 -0
- package/types/domain/components/ConfirmModel.d.ts +20 -35
- package/types/domain/components/EmptyStateModel.d.ts +40 -0
- package/types/domain/components/FAQModel.d.ts +27 -0
- package/types/domain/components/FooterConfigModel.d.ts +21 -0
- package/types/domain/components/FooterVisibilityModel.d.ts +43 -0
- package/types/domain/components/GalleryModel.d.ts +35 -0
- package/types/domain/components/HeaderConfigModel.d.ts +21 -0
- package/types/domain/components/HeaderVisibilityModel.d.ts +49 -0
- package/types/domain/components/HeroModel.d.ts +24 -0
- package/types/domain/components/InputModel.d.ts +19 -59
- package/types/domain/components/PriceModel.d.ts +25 -0
- package/types/domain/components/PricingModel.d.ts +34 -0
- package/types/domain/components/PricingSectionModel.d.ts +27 -0
- package/types/domain/components/ProfileDropdownModel.d.ts +40 -0
- package/types/domain/components/SelectModel.d.ts +13 -28
- package/types/domain/components/ShowcaseAppModel.d.ts +32 -0
- package/types/domain/components/SpinnerModel.d.ts +10 -27
- package/types/domain/components/StatsItemModel.d.ts +33 -0
- package/types/domain/components/StatsModel.d.ts +27 -0
- package/types/domain/components/TableModel.d.ts +10 -26
- package/types/domain/components/TabsModel.d.ts +28 -0
- package/types/domain/components/TestimonialModel.d.ts +18 -0
- package/types/domain/components/TimelineItemModel.d.ts +33 -0
- package/types/domain/components/TimelineModel.d.ts +27 -0
- package/types/domain/components/ToastModel.d.ts +16 -45
- package/types/domain/components/TreeModel.d.ts +13 -36
- package/types/domain/components/index.d.ts +20 -0
- package/types/domain/index.d.ts +4 -1
- package/types/index.d.ts +1 -0
- package/types/testing/GalleryGenerator.d.ts +1 -0
- package/types/testing/LogicInspector.d.ts +22 -0
- package/types/testing/SnapshotInspector.d.ts +17 -0
- package/types/testing/VisualAdapter.d.ts +15 -0
- package/types/testing/index.d.ts +3 -0
- package/src/README.md.js +0 -436
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
|
+
import { PriceModel } from './PriceModel.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* PricingModel — OLMUI Model-as-Schema
|
|
6
|
+
* A pricing tier/plan with title, price, and feature list.
|
|
7
|
+
*/
|
|
8
|
+
export class PricingModel extends Model {
|
|
9
|
+
static $id = '@nan0web/ui/PricingModel'
|
|
10
|
+
|
|
11
|
+
static title = {
|
|
12
|
+
help: 'Pricing plan name',
|
|
13
|
+
placeholder: 'Pro Plan',
|
|
14
|
+
default: '',
|
|
15
|
+
required: true,
|
|
16
|
+
}
|
|
17
|
+
static price = {
|
|
18
|
+
help: 'Price object (value + currency)',
|
|
19
|
+
type: 'PriceModel',
|
|
20
|
+
hint: PriceModel,
|
|
21
|
+
default: null,
|
|
22
|
+
}
|
|
23
|
+
static features = {
|
|
24
|
+
help: 'List of features included in this plan',
|
|
25
|
+
type: 'string[]',
|
|
26
|
+
default: [],
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {Partial<PricingModel> | Record<string, any>} data Model input data.
|
|
31
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
32
|
+
*/
|
|
33
|
+
constructor(data = {}, options = {}) {
|
|
34
|
+
super(data, options)
|
|
35
|
+
/** @type {string} Pricing plan name */ this.title
|
|
36
|
+
/** @type {PriceModel|null} Price object (value + currency) */ this.price
|
|
37
|
+
/** @type {string[]} List of features included in this plan */ this.features
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
|
+
import { PricingModel } from './PricingModel.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* PricingSectionModel — OLMUI Model-as-Schema
|
|
6
|
+
* A section containing a title and a collection of pricing tiers.
|
|
7
|
+
*/
|
|
8
|
+
export class PricingSectionModel extends Model {
|
|
9
|
+
static $id = '@nan0web/ui/PricingSectionModel'
|
|
10
|
+
|
|
11
|
+
static title = {
|
|
12
|
+
help: 'Section title',
|
|
13
|
+
placeholder: 'Pricing Plans',
|
|
14
|
+
default: '',
|
|
15
|
+
}
|
|
16
|
+
static items = {
|
|
17
|
+
help: 'Array of pricing tiers',
|
|
18
|
+
type: 'PricingModel[]',
|
|
19
|
+
hint: PricingModel,
|
|
20
|
+
default: [],
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {Partial<PricingSectionModel> | Record<string, any>} data Model input data.
|
|
25
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
26
|
+
*/
|
|
27
|
+
constructor(data = {}, options = {}) {
|
|
28
|
+
super(data, options)
|
|
29
|
+
/** @type {string} Section title */ this.title
|
|
30
|
+
/** @type {PricingModel[]} Array of pricing tiers */ this.items
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
|
+
import Navigation from '../Navigation.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ProfileDropdownModel — OLMUI Model-as-Schema
|
|
6
|
+
* Account/profile dropdown in the header (user menu).
|
|
7
|
+
*/
|
|
8
|
+
export class ProfileDropdownModel extends Model {
|
|
9
|
+
static $id = '@nan0web/ui/ProfileDropdownModel'
|
|
10
|
+
|
|
11
|
+
static profileName = {
|
|
12
|
+
alias: 'name',
|
|
13
|
+
help: 'Display name of the user',
|
|
14
|
+
placeholder: 'Jane Doe',
|
|
15
|
+
default: '',
|
|
16
|
+
}
|
|
17
|
+
static email = {
|
|
18
|
+
help: 'User email address',
|
|
19
|
+
placeholder: 'jane@example.com',
|
|
20
|
+
default: '',
|
|
21
|
+
}
|
|
22
|
+
static avatar = {
|
|
23
|
+
help: 'User avatar image URL',
|
|
24
|
+
placeholder: 'https://...',
|
|
25
|
+
default: '',
|
|
26
|
+
}
|
|
27
|
+
static actions = {
|
|
28
|
+
help: 'Dropdown menu items (Settings, Logout, etc.)',
|
|
29
|
+
type: 'Navigation[]',
|
|
30
|
+
hint: Navigation,
|
|
31
|
+
default: [],
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {Partial<ProfileDropdownModel> | Record<string, any>} data Model input data.
|
|
36
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
37
|
+
*/
|
|
38
|
+
constructor(data = {}, options = {}) {
|
|
39
|
+
super(data, options)
|
|
40
|
+
/** @type {string} Display name of the user */ this.profileName
|
|
41
|
+
/** @type {string} User email address */ this.email
|
|
42
|
+
/** @type {string} User avatar image URL */ this.avatar
|
|
43
|
+
/** @type {Navigation[]} Dropdown menu items */ this.actions
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -1,20 +1,10 @@
|
|
|
1
|
-
import { Model } from '@nan0web/
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @typedef {Object} SelectData
|
|
5
|
-
* @property {string} [content]
|
|
6
|
-
* @property {string[]} [options]
|
|
7
|
-
*/
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
8
2
|
|
|
9
3
|
/**
|
|
10
4
|
* Model-as-Schema for Select component.
|
|
11
5
|
* Represents a dropdown choice selection.
|
|
12
6
|
*/
|
|
13
7
|
export class SelectModel extends Model {
|
|
14
|
-
// ==========================================
|
|
15
|
-
// 1. MODEL AS SCHEMA (Static Definition)
|
|
16
|
-
// ==========================================
|
|
17
|
-
|
|
18
8
|
static content = {
|
|
19
9
|
help: 'Currently selected item or default placeholder',
|
|
20
10
|
default: 'Choose option',
|
|
@@ -28,18 +18,18 @@ export class SelectModel extends Model {
|
|
|
28
18
|
}
|
|
29
19
|
|
|
30
20
|
/**
|
|
31
|
-
* @param {
|
|
21
|
+
* @param {Partial<SelectModel> | Record<string, any>} data Model input data.
|
|
22
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
32
23
|
*/
|
|
33
|
-
constructor(data = {}) {
|
|
34
|
-
super(data)
|
|
35
|
-
/** @type {string
|
|
36
|
-
/** @type {string[]
|
|
24
|
+
constructor(data = {}, options = {}) {
|
|
25
|
+
super(data, options)
|
|
26
|
+
/** @type {string} Currently selected item or default placeholder */ this.content
|
|
27
|
+
/** @type {string[]} List of available options for selection */ this.options
|
|
37
28
|
}
|
|
38
29
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
30
|
+
/**
|
|
31
|
+
* @returns {AsyncGenerator<any, { type: 'result', data: { selected: string } }, any>}
|
|
32
|
+
*/
|
|
43
33
|
async *run() {
|
|
44
34
|
const response = yield {
|
|
45
35
|
type: 'ask',
|
|
@@ -50,7 +40,7 @@ export class SelectModel extends Model {
|
|
|
50
40
|
validate: (val) => this.options?.includes(val) || 'Invalid option selected',
|
|
51
41
|
},
|
|
52
42
|
component: 'Select',
|
|
53
|
-
model:
|
|
43
|
+
model: this,
|
|
54
44
|
}
|
|
55
45
|
|
|
56
46
|
this.content = response.value
|
|
@@ -1,21 +1,10 @@
|
|
|
1
|
-
import { Model } from '@nan0web/
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @typedef {'sm'|'md'|'lg'} SpinnerSize
|
|
5
|
-
* @typedef {Object} SpinnerData
|
|
6
|
-
* @property {SpinnerSize} [size]
|
|
7
|
-
* @property {string} [color]
|
|
8
|
-
*/
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
9
2
|
|
|
10
3
|
/**
|
|
11
4
|
* Model-as-Schema for Spinner component.
|
|
12
5
|
* Represents a loading or progress state without user interaction.
|
|
13
6
|
*/
|
|
14
7
|
export class SpinnerModel extends Model {
|
|
15
|
-
// ==========================================
|
|
16
|
-
// 1. MODEL AS SCHEMA (Static Definition)
|
|
17
|
-
// ==========================================
|
|
18
|
-
|
|
19
8
|
static size = {
|
|
20
9
|
help: 'Spinner diameter',
|
|
21
10
|
default: 'md',
|
|
@@ -29,30 +18,26 @@ export class SpinnerModel extends Model {
|
|
|
29
18
|
}
|
|
30
19
|
|
|
31
20
|
/**
|
|
32
|
-
* @param {
|
|
21
|
+
* @param {Partial<SpinnerModel> | Record<string, any>} data Model input data.
|
|
22
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
33
23
|
*/
|
|
34
|
-
constructor(data = {}) {
|
|
35
|
-
super(data)
|
|
36
|
-
/** @type {
|
|
37
|
-
/** @type {string
|
|
24
|
+
constructor(data = {}, options = {}) {
|
|
25
|
+
super(data, options)
|
|
26
|
+
/** @type {'sm'|'md'|'lg'} Spinner diameter */ this.size
|
|
27
|
+
/** @type {string} Override for base color token */ this.color
|
|
38
28
|
}
|
|
39
29
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
30
|
+
/**
|
|
31
|
+
* @returns {AsyncGenerator<any, any, any>}
|
|
32
|
+
*/
|
|
44
33
|
async *run() {
|
|
45
|
-
// A spinner does not ask for anything, it simply indicates progress.
|
|
46
|
-
// However, as a pure component it doesn't do any work itself,
|
|
47
|
-
// so running it just means declaring its state.
|
|
48
34
|
yield {
|
|
49
35
|
type: 'progress',
|
|
50
36
|
message: 'Loading...',
|
|
51
37
|
component: 'Spinner',
|
|
52
|
-
model:
|
|
38
|
+
model: this,
|
|
53
39
|
}
|
|
54
40
|
|
|
55
|
-
// Instant exit since it performs no async task internally
|
|
56
41
|
return { type: 'result', data: { completed: true } }
|
|
57
42
|
}
|
|
58
43
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* StatsItemModel — OLMUI Model-as-Schema
|
|
5
|
+
* A single stat entry (e.g. "Users: 10,000 ↑12%").
|
|
6
|
+
*/
|
|
7
|
+
export class StatsItemModel extends Model {
|
|
8
|
+
static $id = '@nan0web/ui/StatsItemModel'
|
|
9
|
+
|
|
10
|
+
static label = {
|
|
11
|
+
help: 'Stat label (e.g. "Active Users")',
|
|
12
|
+
placeholder: 'Users',
|
|
13
|
+
default: '',
|
|
14
|
+
required: true,
|
|
15
|
+
}
|
|
16
|
+
static value = {
|
|
17
|
+
help: 'Stat value (number or formatted string)',
|
|
18
|
+
placeholder: '10,000',
|
|
19
|
+
default: '',
|
|
20
|
+
required: true,
|
|
21
|
+
}
|
|
22
|
+
static trend = {
|
|
23
|
+
help: 'Trend indicator (e.g. "+12%", "-3%", or empty)',
|
|
24
|
+
placeholder: '+12%',
|
|
25
|
+
default: '',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {Partial<StatsItemModel> | Record<string, any>} data Model input data.
|
|
30
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
31
|
+
*/
|
|
32
|
+
constructor(data = {}, options = {}) {
|
|
33
|
+
super(data, options)
|
|
34
|
+
/** @type {string} Stat label (e.g. "Active Users") */ this.label
|
|
35
|
+
/** @type {string} Stat value (number or formatted string) */ this.value
|
|
36
|
+
/** @type {string} Trend indicator (e.g. "+12%", "-3%", or empty) */ this.trend
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
|
+
import { StatsItemModel } from './StatsItemModel.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* StatsModel — OLMUI Model-as-Schema
|
|
6
|
+
* A collection of stat items for dashboards and overview sections.
|
|
7
|
+
*/
|
|
8
|
+
export class StatsModel extends Model {
|
|
9
|
+
static $id = '@nan0web/ui/StatsModel'
|
|
10
|
+
|
|
11
|
+
static title = {
|
|
12
|
+
help: 'Stats section title',
|
|
13
|
+
placeholder: 'Key Metrics',
|
|
14
|
+
default: '',
|
|
15
|
+
}
|
|
16
|
+
static items = {
|
|
17
|
+
help: 'Array of stat entries',
|
|
18
|
+
type: 'StatsItemModel[]',
|
|
19
|
+
hint: StatsItemModel,
|
|
20
|
+
default: [],
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {Partial<StatsModel> | Record<string, any>} data Model input data.
|
|
25
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
26
|
+
*/
|
|
27
|
+
constructor(data = {}, options = {}) {
|
|
28
|
+
super(data, options)
|
|
29
|
+
/** @type {string} Stats section title */ this.title
|
|
30
|
+
/** @type {StatsItemModel[]} Array of stat entries */ this.items
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -1,20 +1,10 @@
|
|
|
1
|
-
import { Model } from '@nan0web/
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @typedef {Object} TableData
|
|
5
|
-
* @property {string[]} [columns]
|
|
6
|
-
* @property {string[][]} [rows]
|
|
7
|
-
*/
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
8
2
|
|
|
9
3
|
/**
|
|
10
4
|
* Model-as-Schema for Table Data component.
|
|
11
5
|
* Displays tabular string data in rows and columns.
|
|
12
6
|
*/
|
|
13
7
|
export class TableModel extends Model {
|
|
14
|
-
// ==========================================
|
|
15
|
-
// 1. MODEL AS SCHEMA (Static Definition)
|
|
16
|
-
// ==========================================
|
|
17
|
-
|
|
18
8
|
static columns = {
|
|
19
9
|
help: 'Array of column headers',
|
|
20
10
|
type: 'string[]',
|
|
@@ -31,28 +21,25 @@ export class TableModel extends Model {
|
|
|
31
21
|
}
|
|
32
22
|
|
|
33
23
|
/**
|
|
34
|
-
* @param {
|
|
24
|
+
* @param {Partial<TableModel> | Record<string, any>} data Model input data.
|
|
25
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
35
26
|
*/
|
|
36
|
-
constructor(data = {}) {
|
|
37
|
-
super(data)
|
|
38
|
-
/** @type {string[]
|
|
39
|
-
/** @type {string[][]
|
|
27
|
+
constructor(data = {}, options = {}) {
|
|
28
|
+
super(data, options)
|
|
29
|
+
/** @type {string[]} Array of column headers */ this.columns
|
|
30
|
+
/** @type {string[][]} 2D Array of table cells matching column length */ this.rows
|
|
40
31
|
}
|
|
41
32
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
33
|
+
/**
|
|
34
|
+
* @returns {AsyncGenerator<any, any, any>}
|
|
35
|
+
*/
|
|
46
36
|
async *run() {
|
|
47
|
-
// Tables are naturally result or log displays.
|
|
48
|
-
// For an interactive flow, we could ask the user to 'select' a row,
|
|
49
|
-
// but by default a table simply presents data.
|
|
50
37
|
yield {
|
|
51
38
|
type: 'log',
|
|
52
39
|
level: 'info',
|
|
53
40
|
message: `Displaying table with ${this.rows?.length || 0} rows`,
|
|
54
41
|
component: 'Table',
|
|
55
|
-
model:
|
|
42
|
+
model: this,
|
|
56
43
|
}
|
|
57
44
|
|
|
58
45
|
return { type: 'result', data: { rowsCount: this.rows?.length || 0 } }
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* TabsModel — OLMUI Model-as-Schema
|
|
5
|
+
* Tab container with selectable panels.
|
|
6
|
+
*/
|
|
7
|
+
export class TabsModel extends Model {
|
|
8
|
+
static $id = '@nan0web/ui/TabsModel'
|
|
9
|
+
|
|
10
|
+
static active = {
|
|
11
|
+
help: 'Index of the currently active tab',
|
|
12
|
+
default: 0,
|
|
13
|
+
type: 'number',
|
|
14
|
+
}
|
|
15
|
+
static tabs = {
|
|
16
|
+
help: 'Tab definitions (label + content pairs)',
|
|
17
|
+
type: 'object[]',
|
|
18
|
+
default: [],
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {Partial<TabsModel> | Record<string, any>} data Model input data.
|
|
23
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
24
|
+
*/
|
|
25
|
+
constructor(data = {}, options = {}) {
|
|
26
|
+
super(data, options)
|
|
27
|
+
/** @type {number} Index of the currently active tab */ this.active
|
|
28
|
+
/** @type {Array<{label: string, content: string}>} Tab definitions */ this.tabs
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CommentModel } from './CommentModel.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* TestimonialModel — OLMUI Model-as-Schema
|
|
5
|
+
* Extends CommentModel with a rating field for testimonials/reviews.
|
|
6
|
+
*/
|
|
7
|
+
export class TestimonialModel extends CommentModel {
|
|
8
|
+
static $id = '@nan0web/ui/TestimonialModel'
|
|
9
|
+
|
|
10
|
+
static rating = {
|
|
11
|
+
help: 'Rating from 1 to 5 stars',
|
|
12
|
+
default: 5,
|
|
13
|
+
type: 'number',
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {Partial<TestimonialModel> | Record<string, any>} data Model input data.
|
|
18
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
19
|
+
*/
|
|
20
|
+
constructor(data = {}, options = {}) {
|
|
21
|
+
super(data, options)
|
|
22
|
+
/** @type {number} Rating from 1 to 5 stars */ this.rating
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* TimelineItemModel — OLMUI Model-as-Schema
|
|
5
|
+
* A single entry on a timeline (event, milestone, changelog).
|
|
6
|
+
*/
|
|
7
|
+
export class TimelineItemModel extends Model {
|
|
8
|
+
static $id = '@nan0web/ui/TimelineItemModel'
|
|
9
|
+
|
|
10
|
+
static date = {
|
|
11
|
+
help: 'Date of the event (ISO 8601 or display string)',
|
|
12
|
+
placeholder: '2026-01-15',
|
|
13
|
+
default: '',
|
|
14
|
+
required: true,
|
|
15
|
+
}
|
|
16
|
+
static title = {
|
|
17
|
+
help: 'Event or milestone title',
|
|
18
|
+
placeholder: 'Product Launch',
|
|
19
|
+
default: '',
|
|
20
|
+
required: true,
|
|
21
|
+
}
|
|
22
|
+
static description = {
|
|
23
|
+
help: 'Detailed description of the event',
|
|
24
|
+
placeholder: 'We launched our new product...',
|
|
25
|
+
default: '',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {Partial<TimelineItemModel> | Record<string, any>} data Model input data.
|
|
30
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
31
|
+
*/
|
|
32
|
+
constructor(data = {}, options = {}) {
|
|
33
|
+
super(data, options)
|
|
34
|
+
/** @type {string} Date of the event */ this.date
|
|
35
|
+
/** @type {string} Event or milestone title */ this.title
|
|
36
|
+
/** @type {string} Detailed description of the event */ this.description
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
|
+
import { TimelineItemModel } from './TimelineItemModel.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* TimelineModel — OLMUI Model-as-Schema
|
|
6
|
+
* A collection of timeline events (changelog, roadmap, history).
|
|
7
|
+
*/
|
|
8
|
+
export class TimelineModel extends Model {
|
|
9
|
+
static $id = '@nan0web/ui/TimelineModel'
|
|
10
|
+
|
|
11
|
+
static title = {
|
|
12
|
+
help: 'Timeline section title',
|
|
13
|
+
placeholder: 'Our Journey',
|
|
14
|
+
default: '',
|
|
15
|
+
}
|
|
16
|
+
static items = {
|
|
17
|
+
help: 'Array of timeline events',
|
|
18
|
+
type: 'TimelineItemModel[]',
|
|
19
|
+
hint: TimelineItemModel,
|
|
20
|
+
default: [],
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {Partial<TimelineModel> | Record<string, any>} data Model input data.
|
|
25
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
26
|
+
*/
|
|
27
|
+
constructor(data = {}, options = {}) {
|
|
28
|
+
super(data, options)
|
|
29
|
+
/** @type {string} Timeline section title */ this.title
|
|
30
|
+
/** @type {TimelineItemModel[]} Array of timeline events */ this.items
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -1,77 +1,50 @@
|
|
|
1
|
-
import { Model } from '@nan0web/
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* @typedef {Object} ToastData
|
|
6
|
-
* @property {string} [message]
|
|
7
|
-
* @property {ToastVariant} [variant]
|
|
8
|
-
* @property {number} [duration]
|
|
9
|
-
* @property {boolean} [open]
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Model-as-Schema for Toast notification component.
|
|
14
|
-
* Represents a transient message displayed to the user.
|
|
4
|
+
* Model-as-Schema for Toast notification.
|
|
15
5
|
*/
|
|
16
6
|
export class ToastModel extends Model {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
static variant = {
|
|
8
|
+
help: 'Notification color scheme',
|
|
9
|
+
default: 'info',
|
|
10
|
+
options: ['info', 'success', 'warn', 'error'],
|
|
11
|
+
}
|
|
20
12
|
|
|
21
13
|
static message = {
|
|
22
|
-
help: '
|
|
23
|
-
default: '
|
|
14
|
+
help: 'Text content of the notification',
|
|
15
|
+
default: 'Notification message',
|
|
24
16
|
type: 'string',
|
|
25
17
|
}
|
|
26
18
|
|
|
27
|
-
static variant = {
|
|
28
|
-
help: 'Visual styling representing the message severity',
|
|
29
|
-
default: 'success',
|
|
30
|
-
options: ['success', 'error', 'info', 'warning'],
|
|
31
|
-
}
|
|
32
|
-
|
|
33
19
|
static duration = {
|
|
34
|
-
help: '
|
|
20
|
+
help: 'Auto-dismiss timeout (0 for manual only)',
|
|
35
21
|
default: 3000,
|
|
36
22
|
type: 'number',
|
|
37
23
|
}
|
|
38
24
|
|
|
39
|
-
static open = {
|
|
40
|
-
help: 'Controls visibility state',
|
|
41
|
-
default: true,
|
|
42
|
-
type: 'boolean',
|
|
43
|
-
}
|
|
44
|
-
|
|
45
25
|
/**
|
|
46
|
-
* @param {
|
|
26
|
+
* @param {Partial<ToastModel> | Record<string, any>} data Model input data.
|
|
27
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
47
28
|
*/
|
|
48
|
-
constructor(data = {}) {
|
|
49
|
-
super(data)
|
|
50
|
-
/** @type {
|
|
51
|
-
/** @type {
|
|
52
|
-
/** @type {number
|
|
53
|
-
/** @type {boolean|undefined} */ this.open
|
|
29
|
+
constructor(data = {}, options = {}) {
|
|
30
|
+
super(data, options)
|
|
31
|
+
/** @type {'info'|'success'|'warn'|'error'} Notification color scheme */ this.variant
|
|
32
|
+
/** @type {string} Text displayed in the toast */ this.message
|
|
33
|
+
/** @type {number} Auto-dismiss timeout in ms */ this.duration
|
|
54
34
|
}
|
|
55
35
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
36
|
+
/**
|
|
37
|
+
* @returns {AsyncGenerator<any, any, any>}
|
|
38
|
+
*/
|
|
60
39
|
async *run() {
|
|
61
|
-
// Maps naturally to the 'log' intent for OLMUI runners.
|
|
62
40
|
yield {
|
|
63
41
|
type: 'log',
|
|
64
|
-
level: this.variant === 'error' ? 'error' :
|
|
42
|
+
level: this.variant === 'error' ? 'error' : 'info',
|
|
65
43
|
message: this.message,
|
|
66
|
-
component: 'Toast',
|
|
67
|
-
model:
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Wait exactly 'duration' ms before completing (unless duration is 0)
|
|
71
|
-
if (this.duration && this.duration > 0) {
|
|
72
|
-
await new Promise((resolve) => setTimeout(resolve, this.duration))
|
|
44
|
+
component: 'Toast',
|
|
45
|
+
model: this,
|
|
73
46
|
}
|
|
74
47
|
|
|
75
|
-
return { type: 'result', data: {
|
|
48
|
+
return { type: 'result', data: { shown: true } }
|
|
76
49
|
}
|
|
77
50
|
}
|
|
@@ -1,26 +1,10 @@
|
|
|
1
|
-
import { Model } from '@nan0web/
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @typedef {Object} TreeNode
|
|
5
|
-
* @property {string} label
|
|
6
|
-
* @property {boolean} [expanded]
|
|
7
|
-
* @property {TreeNode[]} [children]
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @typedef {Object} TreeData
|
|
12
|
-
* @property {TreeNode[]} [data]
|
|
13
|
-
*/
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
14
2
|
|
|
15
3
|
/**
|
|
16
4
|
* Model-as-Schema for Tree component.
|
|
17
5
|
* Represents a hierarchical selection or navigation structure.
|
|
18
6
|
*/
|
|
19
7
|
export class TreeModel extends Model {
|
|
20
|
-
// ==========================================
|
|
21
|
-
// 1. MODEL AS SCHEMA (Static Definition)
|
|
22
|
-
// ==========================================
|
|
23
|
-
|
|
24
8
|
static data = {
|
|
25
9
|
help: 'Tree nodes defining the hierarchy',
|
|
26
10
|
type: 'TreeNode[]',
|
|
@@ -28,24 +12,24 @@ export class TreeModel extends Model {
|
|
|
28
12
|
}
|
|
29
13
|
|
|
30
14
|
/**
|
|
31
|
-
* @param {
|
|
15
|
+
* @param {Partial<TreeModel> | Record<string, any>} data Model input data.
|
|
16
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
32
17
|
*/
|
|
33
|
-
constructor(data = {}) {
|
|
34
|
-
super(data)
|
|
35
|
-
/** @type {
|
|
18
|
+
constructor(data = {}, options = {}) {
|
|
19
|
+
super(data, options)
|
|
20
|
+
/** @type {Array<{label: string, expanded?: boolean, children?: any[]}>} Tree nodes */ this.data
|
|
36
21
|
}
|
|
37
22
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
23
|
+
/**
|
|
24
|
+
* @returns {AsyncGenerator<any, any, any>}
|
|
25
|
+
*/
|
|
42
26
|
async *run() {
|
|
43
27
|
const response = yield {
|
|
44
28
|
type: 'ask',
|
|
45
29
|
field: 'selectedNode',
|
|
46
30
|
schema: { help: 'Select a node from the tree' },
|
|
47
31
|
component: 'Tree',
|
|
48
|
-
model:
|
|
32
|
+
model: this,
|
|
49
33
|
}
|
|
50
34
|
|
|
51
35
|
return { type: 'result', data: { selected: response.value } }
|