terrier-engine 4.0.21 → 4.3.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/app.ts +37 -27
- package/dropdowns.ts +27 -22
- package/forms.ts +33 -0
- package/fragments.ts +39 -37
- package/gen/hub-icons.ts +697 -0
- package/glyps.ts +2 -2
- package/images/icons/active.svg +1 -0
- package/images/icons/admin.svg +1 -0
- package/images/icons/archive.svg +1 -0
- package/images/icons/arrow_down.svg +1 -0
- package/images/icons/arrow_left.svg +1 -0
- package/images/icons/arrow_right.svg +1 -0
- package/images/icons/arrow_up.svg +1 -0
- package/images/icons/assign.svg +1 -0
- package/images/icons/attachment.svg +1 -0
- package/images/icons/back.svg +1 -0
- package/images/icons/badge.svg +1 -0
- package/images/icons/board.svg +1 -0
- package/images/icons/branch.svg +1 -0
- package/images/icons/bug.svg +1 -0
- package/images/icons/calculator.svg +1 -0
- package/images/icons/checkmark.svg +1 -0
- package/images/icons/close.svg +1 -0
- package/images/icons/clypboard.svg +1 -0
- package/images/icons/comment.svg +1 -0
- package/images/icons/complete.svg +1 -0
- package/images/icons/dashboard.svg +1 -0
- package/images/icons/data_pull.svg +1 -0
- package/images/icons/data_update.svg +1 -0
- package/images/icons/database.svg +1 -0
- package/images/icons/day.svg +1 -0
- package/images/icons/delete.svg +1 -0
- package/images/icons/documentation.svg +1 -0
- package/images/icons/edit.svg +1 -0
- package/images/icons/feature.svg +1 -0
- package/images/icons/flex.svg +1 -0
- package/images/icons/forward.svg +1 -0
- package/images/icons/github.svg +1 -0
- package/images/icons/history.svg +1 -0
- package/images/icons/home.svg +1 -0
- package/images/icons/image.svg +1 -0
- package/images/icons/inbox.svg +1 -0
- package/images/icons/info.svg +1 -0
- package/images/icons/issue.svg +1 -0
- package/images/icons/lane.svg +1 -0
- package/images/icons/lane_asap.svg +1 -0
- package/images/icons/lane_days.svg +1 -0
- package/images/icons/lane_hours.svg +1 -0
- package/images/icons/lane_weeks.svg +1 -0
- package/images/icons/lanes_board.svg +1 -0
- package/images/icons/level_complete.svg +1 -0
- package/images/icons/level_highway.svg +1 -0
- package/images/icons/level_on_ramp.svg +1 -0
- package/images/icons/level_parking.svg +1 -0
- package/images/icons/minus.svg +1 -0
- package/images/icons/night.svg +1 -0
- package/images/icons/origin.svg +1 -0
- package/images/icons/pending.svg +1 -0
- package/images/icons/plus.svg +1 -0
- package/images/icons/post.svg +1 -0
- package/images/icons/pr_closed.svg +1 -0
- package/images/icons/pr_merged.svg +1 -0
- package/images/icons/pr_open.svg +1 -0
- package/images/icons/prioritized.svg +1 -0
- package/images/icons/project.svg +1 -0
- package/images/icons/question.svg +1 -0
- package/images/icons/reaction.svg +1 -0
- package/images/icons/recent.svg +1 -0
- package/images/icons/refresh.svg +1 -0
- package/images/icons/request.svg +1 -0
- package/images/icons/settings.svg +1 -0
- package/images/icons/status.svg +1 -0
- package/images/icons/step_deploy.svg +1 -0
- package/images/icons/step_develop.svg +1 -0
- package/images/icons/step_investigate.svg +1 -0
- package/images/icons/step_review.svg +1 -0
- package/images/icons/step_test.svg +1 -0
- package/images/icons/steps.svg +1 -0
- package/images/icons/steps_board.svg +1 -0
- package/images/icons/subscribe.svg +1 -0
- package/images/icons/support.svg +1 -0
- package/images/icons/terrier.svg +1 -0
- package/images/icons/thumbs_up.svg +1 -0
- package/images/icons/type.svg +1 -0
- package/images/icons/unprioritized.svg +1 -0
- package/images/icons/upload.svg +1 -0
- package/images/icons/user.svg +1 -0
- package/images/icons/users.svg +1 -0
- package/images/optimized/icon-active.svg +1 -0
- package/images/optimized/icon-admin.svg +1 -0
- package/images/optimized/icon-archive.svg +1 -0
- package/images/optimized/icon-arrow_down.svg +1 -0
- package/images/optimized/icon-arrow_left.svg +1 -0
- package/images/optimized/icon-arrow_right.svg +1 -0
- package/images/optimized/icon-arrow_up.svg +1 -0
- package/images/optimized/icon-assign.svg +1 -0
- package/images/optimized/icon-attachment.svg +1 -0
- package/images/optimized/icon-back.svg +1 -0
- package/images/optimized/icon-badge.svg +1 -0
- package/images/optimized/icon-board.svg +1 -0
- package/images/optimized/icon-branch.svg +1 -0
- package/images/optimized/icon-bug.svg +1 -0
- package/images/optimized/icon-calculator.svg +1 -0
- package/images/optimized/icon-checkmark.svg +1 -0
- package/images/optimized/icon-close.svg +1 -0
- package/images/optimized/icon-clypboard.svg +1 -0
- package/images/optimized/icon-comment.svg +1 -0
- package/images/optimized/icon-complete.svg +1 -0
- package/images/optimized/icon-dashboard.svg +1 -0
- package/images/optimized/icon-data_pull.svg +1 -0
- package/images/optimized/icon-data_update.svg +1 -0
- package/images/optimized/icon-database.svg +1 -0
- package/images/optimized/icon-day.svg +1 -0
- package/images/optimized/icon-delete.svg +1 -0
- package/images/optimized/icon-documentation.svg +1 -0
- package/images/optimized/icon-edit.svg +1 -0
- package/images/optimized/icon-feature.svg +1 -0
- package/images/optimized/icon-flex.svg +1 -0
- package/images/optimized/icon-forward.svg +1 -0
- package/images/optimized/icon-github.svg +1 -0
- package/images/optimized/icon-history.svg +1 -0
- package/images/optimized/icon-home.svg +1 -0
- package/images/optimized/icon-image.svg +1 -0
- package/images/optimized/icon-inbox.svg +1 -0
- package/images/optimized/icon-info.svg +1 -0
- package/images/optimized/icon-issue.svg +1 -0
- package/images/optimized/icon-lane.svg +1 -0
- package/images/optimized/icon-lane_asap.svg +1 -0
- package/images/optimized/icon-lane_days.svg +1 -0
- package/images/optimized/icon-lane_hours.svg +1 -0
- package/images/optimized/icon-lane_weeks.svg +1 -0
- package/images/optimized/icon-lanes_board.svg +1 -0
- package/images/optimized/icon-level_complete.svg +1 -0
- package/images/optimized/icon-level_highway.svg +1 -0
- package/images/optimized/icon-level_on_ramp.svg +1 -0
- package/images/optimized/icon-level_parking.svg +1 -0
- package/images/optimized/icon-minus.svg +1 -0
- package/images/optimized/icon-night.svg +1 -0
- package/images/optimized/icon-origin.svg +1 -0
- package/images/optimized/icon-pending.svg +1 -0
- package/images/optimized/icon-plus.svg +1 -0
- package/images/optimized/icon-post.svg +1 -0
- package/images/optimized/icon-pr_closed.svg +1 -0
- package/images/optimized/icon-pr_merged.svg +1 -0
- package/images/optimized/icon-pr_open.svg +1 -0
- package/images/optimized/icon-prioritized.svg +1 -0
- package/images/optimized/icon-project.svg +1 -0
- package/images/optimized/icon-question.svg +1 -0
- package/images/optimized/icon-reaction.svg +1 -0
- package/images/optimized/icon-recent.svg +1 -0
- package/images/optimized/icon-refresh.svg +1 -0
- package/images/optimized/icon-request.svg +1 -0
- package/images/optimized/icon-settings.svg +1 -0
- package/images/optimized/icon-status.svg +1 -0
- package/images/optimized/icon-step_deploy.svg +1 -0
- package/images/optimized/icon-step_develop.svg +1 -0
- package/images/optimized/icon-step_investigate.svg +1 -0
- package/images/optimized/icon-step_review.svg +1 -0
- package/images/optimized/icon-step_test.svg +1 -0
- package/images/optimized/icon-steps.svg +1 -0
- package/images/optimized/icon-steps_board.svg +1 -0
- package/images/optimized/icon-subscribe.svg +1 -0
- package/images/optimized/icon-support.svg +1 -0
- package/images/optimized/icon-terrier.svg +1 -0
- package/images/optimized/icon-thumbs_up.svg +1 -0
- package/images/optimized/icon-type.svg +1 -0
- package/images/optimized/icon-unprioritized.svg +1 -0
- package/images/optimized/icon-upload.svg +1 -0
- package/images/optimized/icon-user.svg +1 -0
- package/images/optimized/icon-users.svg +1 -0
- package/images/optimized/terrier-hub-favicon.svg +1 -0
- package/images/optimized/terrier-hub-icon-dark.svg +1 -0
- package/images/optimized/terrier-hub-icon-light.svg +1 -0
- package/images/optimized/terrier-hub-loader.svg +1 -0
- package/images/optimized/terrier-hub-logo-dark.svg +1 -0
- package/images/optimized/terrier-hub-logo-light.svg +1 -0
- package/images/raw/icon-active.svg +8 -0
- package/images/raw/icon-admin.svg +9 -0
- package/images/raw/icon-archive.svg +9 -0
- package/images/raw/icon-arrow_down.svg +7 -0
- package/images/raw/icon-arrow_left.svg +7 -0
- package/images/raw/icon-arrow_right.svg +7 -0
- package/images/raw/icon-arrow_up.svg +7 -0
- package/images/raw/icon-assign.svg +8 -0
- package/images/raw/icon-attachment.svg +7 -0
- package/images/raw/icon-back.svg +7 -0
- package/images/raw/icon-badge.svg +10 -0
- package/images/raw/icon-board.svg +20 -0
- package/images/raw/icon-branch.svg +11 -0
- package/images/raw/icon-bug.svg +8 -0
- package/images/raw/icon-calculator.svg +31 -0
- package/images/raw/icon-checkmark.svg +8 -0
- package/images/raw/icon-close.svg +8 -0
- package/images/raw/icon-clypboard.svg +9 -0
- package/images/raw/icon-comment.svg +12 -0
- package/images/raw/icon-complete.svg +8 -0
- package/images/raw/icon-dashboard.svg +18 -0
- package/images/raw/icon-data_pull.svg +9 -0
- package/images/raw/icon-data_update.svg +9 -0
- package/images/raw/icon-database.svg +10 -0
- package/images/raw/icon-day.svg +19 -0
- package/images/raw/icon-delete.svg +11 -0
- package/images/raw/icon-documentation.svg +21 -0
- package/images/raw/icon-edit.svg +11 -0
- package/images/raw/icon-feature.svg +7 -0
- package/images/raw/icon-flex.svg +6 -0
- package/images/raw/icon-forward.svg +7 -0
- package/images/raw/icon-github.svg +8 -0
- package/images/raw/icon-history.svg +12 -0
- package/images/raw/icon-home.svg +8 -0
- package/images/raw/icon-image.svg +9 -0
- package/images/raw/icon-inbox.svg +9 -0
- package/images/raw/icon-info.svg +11 -0
- package/images/raw/icon-issue.svg +10 -0
- package/images/raw/icon-lane.svg +9 -0
- package/images/raw/icon-lane_asap.svg +9 -0
- package/images/raw/icon-lane_days.svg +11 -0
- package/images/raw/icon-lane_hours.svg +8 -0
- package/images/raw/icon-lane_weeks.svg +10 -0
- package/images/raw/icon-lanes_board.svg +10 -0
- package/images/raw/icon-level_complete.svg +8 -0
- package/images/raw/icon-level_highway.svg +11 -0
- package/images/raw/icon-level_on_ramp.svg +8 -0
- package/images/raw/icon-level_parking.svg +10 -0
- package/images/raw/icon-minus.svg +8 -0
- package/images/raw/icon-night.svg +9 -0
- package/images/raw/icon-origin.svg +11 -0
- package/images/raw/icon-pending.svg +10 -0
- package/images/raw/icon-plus.svg +8 -0
- package/images/raw/icon-post.svg +12 -0
- package/images/raw/icon-pr_closed.svg +15 -0
- package/images/raw/icon-pr_merged.svg +11 -0
- package/images/raw/icon-pr_open.svg +12 -0
- package/images/raw/icon-prioritized.svg +11 -0
- package/images/raw/icon-project.svg +24 -0
- package/images/raw/icon-question.svg +9 -0
- package/images/raw/icon-reaction.svg +6 -0
- package/images/raw/icon-recent.svg +12 -0
- package/images/raw/icon-refresh.svg +11 -0
- package/images/raw/icon-request.svg +10 -0
- package/images/raw/icon-settings.svg +11 -0
- package/images/raw/icon-status.svg +8 -0
- package/images/raw/icon-step_deploy.svg +15 -0
- package/images/raw/icon-step_develop.svg +12 -0
- package/images/raw/icon-step_investigate.svg +14 -0
- package/images/raw/icon-step_review.svg +11 -0
- package/images/raw/icon-step_test.svg +14 -0
- package/images/raw/icon-steps.svg +18 -0
- package/images/raw/icon-steps_board.svg +19 -0
- package/images/raw/icon-subscribe.svg +10 -0
- package/images/raw/icon-support.svg +14 -0
- package/images/raw/icon-terrier.svg +7 -0
- package/images/raw/icon-thumbs_up.svg +1 -0
- package/images/raw/icon-type.svg +15 -0
- package/images/raw/icon-unprioritized.svg +10 -0
- package/images/raw/icon-upload.svg +8 -0
- package/images/raw/icon-user.svg +9 -0
- package/images/raw/icon-users.svg +14 -0
- package/images/raw/terrier-hub-favicon-alert.png +0 -0
- package/images/raw/terrier-hub-favicon-dark.png +0 -0
- package/images/raw/terrier-hub-favicon.png +0 -0
- package/images/raw/terrier-hub-favicon.svg +29 -0
- package/images/raw/terrier-hub-icon-dark.svg +23 -0
- package/images/raw/terrier-hub-icon-light.png +0 -0
- package/images/raw/terrier-hub-icon-light.svg +23 -0
- package/images/raw/terrier-hub-loader.svg +54 -0
- package/images/raw/terrier-hub-logo-dark.svg +27 -0
- package/images/raw/terrier-hub-logo-light.png +0 -0
- package/images/raw/terrier-hub-logo-light.svg +28 -0
- package/lightbox.ts +9 -22
- package/loading.ts +5 -6
- package/modals.ts +8 -19
- package/overlays.ts +100 -33
- package/package.json +1 -1
- package/parts/content-part.ts +187 -0
- package/parts/not-found-page.ts +20 -0
- package/parts/page-part.ts +189 -0
- package/parts/panel-part.ts +40 -0
- package/parts/terrier-form-part.ts +20 -0
- package/parts/terrier-part.ts +89 -0
- package/schema.ts +28 -1
- package/tabs.ts +164 -0
- package/theme.ts +41 -12
- package/toasts.ts +10 -10
- package/tooltips.ts +2 -2
- package/parts.ts +0 -485
package/app.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Logger } from "tuff-core/logging"
|
|
2
|
-
import {Part, PartParent} from "tuff-core/parts"
|
|
3
|
-
import
|
|
2
|
+
import {Part, PartConstructor, PartParent} from "tuff-core/parts"
|
|
3
|
+
import TerrierPart from "./parts/terrier-part"
|
|
4
4
|
import Tooltips from "./tooltips"
|
|
5
5
|
import Lightbox from "./lightbox"
|
|
6
|
+
import Theme from "./theme"
|
|
7
|
+
import {ModalPart, ModalStackPart} from "./modals"
|
|
8
|
+
import {OverlayLayerType, OverlayPart} from "./overlays"
|
|
6
9
|
|
|
7
10
|
// @ts-ignore
|
|
8
11
|
import logoUrl from './images/optimized/terrier-hub-logo-light.svg'
|
|
9
|
-
import Theme, {ThemeType} from "./theme"
|
|
10
|
-
import {ModalPart, ModalStackPart} from "./modals"
|
|
11
|
-
import {OverlayLayer, OverlayPart} from "./overlays"
|
|
12
12
|
|
|
13
13
|
const log = new Logger('App')
|
|
14
14
|
Logger.level = 'info'
|
|
@@ -16,22 +16,18 @@ Logger.level = 'info'
|
|
|
16
16
|
/**
|
|
17
17
|
* Main application part that renders the entire page.
|
|
18
18
|
*/
|
|
19
|
-
export abstract class TerrierApp<
|
|
20
|
-
TThemeType extends ThemeType,
|
|
21
|
-
TSelf extends TerrierApp<TThemeType, TSelf, TTheme>,
|
|
22
|
-
TTheme extends Theme<TThemeType>
|
|
23
|
-
> extends TerrierPart<{theme: TTheme}, TThemeType, TSelf, TTheme> {
|
|
24
|
-
|
|
25
|
-
_theme!: TTheme
|
|
19
|
+
export abstract class TerrierApp<TState> extends TerrierPart<TState> {
|
|
26
20
|
|
|
27
|
-
|
|
21
|
+
_theme!: Theme
|
|
22
|
+
|
|
23
|
+
get theme(): Theme {
|
|
28
24
|
return this._theme
|
|
29
25
|
}
|
|
30
26
|
|
|
31
27
|
overlayPart!: OverlayPart
|
|
32
28
|
|
|
33
29
|
async init() {
|
|
34
|
-
this._theme =
|
|
30
|
+
this._theme = new Theme()
|
|
35
31
|
this.overlayPart = this.makePart(OverlayPart, {})
|
|
36
32
|
log.info("Initialized")
|
|
37
33
|
}
|
|
@@ -44,42 +40,56 @@ export abstract class TerrierApp<
|
|
|
44
40
|
update(root: HTMLElement) {
|
|
45
41
|
log.info(`Update`, root)
|
|
46
42
|
Tooltips.init(root)
|
|
47
|
-
Lightbox.init
|
|
43
|
+
Lightbox.init(root, this, 'body-content')
|
|
48
44
|
}
|
|
49
45
|
|
|
50
46
|
|
|
51
47
|
/// Overlays
|
|
52
48
|
|
|
53
|
-
|
|
49
|
+
addOverlay<OverlayType extends Part<StateType>, StateType extends {}>(
|
|
54
50
|
constructor: { new(p: PartParent, id: string, state: StateType): OverlayType; },
|
|
55
51
|
state: StateType,
|
|
56
|
-
|
|
57
|
-
)
|
|
58
|
-
return this.overlayPart.
|
|
52
|
+
type: OverlayLayerType
|
|
53
|
+
) {
|
|
54
|
+
return this.overlayPart.pushLayer(constructor, state, type)
|
|
59
55
|
}
|
|
60
56
|
|
|
61
|
-
|
|
62
|
-
this.overlayPart.
|
|
63
|
-
|
|
57
|
+
removeOverlay<StateType extends {}>(state: StateType): boolean {
|
|
58
|
+
return this.overlayPart.removeLayer(state)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
popOverlay(type?: OverlayLayerType) {
|
|
62
|
+
this.overlayPart.popLayer(type)
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
clearOverlays() {
|
|
67
66
|
this.overlayPart.clearAll()
|
|
68
67
|
}
|
|
69
68
|
|
|
69
|
+
removeDropdown<StateType>(state: StateType): boolean {
|
|
70
|
+
this.lastDropdownTarget = undefined
|
|
71
|
+
return this.overlayPart.removeLayer(state)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
clearDropdowns() {
|
|
75
|
+
this.lastDropdownTarget = undefined
|
|
76
|
+
this.popOverlay('dropdown')
|
|
77
|
+
}
|
|
78
|
+
|
|
70
79
|
|
|
71
80
|
lastDropdownTarget?: HTMLElement
|
|
72
81
|
|
|
73
82
|
|
|
74
83
|
/// Modals
|
|
75
84
|
|
|
76
|
-
showModal<ModalType extends ModalPart<StateType
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
85
|
+
showModal<ModalType extends ModalPart<StateType>, StateType>(
|
|
86
|
+
constructor: PartConstructor<ModalType, StateType>,
|
|
87
|
+
state: StateType
|
|
88
|
+
): ModalType {
|
|
89
|
+
const modalStack = this.overlayPart.getOrCreateLayer(ModalStackPart, {}, 'modal')
|
|
80
90
|
const modal = modalStack.pushModal(constructor, state)
|
|
81
91
|
modalStack.dirty()
|
|
82
|
-
return modal
|
|
92
|
+
return modal as ModalType
|
|
83
93
|
}
|
|
84
94
|
|
|
85
95
|
|
package/dropdowns.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import {Logger} from "tuff-core/logging"
|
|
2
|
+
import {untypedKey} from "tuff-core/messages"
|
|
3
|
+
import {unique} from "tuff-core/arrays"
|
|
4
4
|
import {PartTag, StatelessPart} from "tuff-core/parts"
|
|
5
5
|
import Overlays from "./overlays"
|
|
6
|
-
import
|
|
6
|
+
import TerrierPart from "./parts/terrier-part"
|
|
7
7
|
import Objects from "tuff-core/objects"
|
|
8
|
-
import
|
|
9
|
-
import {TerrierApp} from "./app";
|
|
8
|
+
import {Action} from "./theme"
|
|
10
9
|
|
|
11
10
|
const log = new Logger('Dropdowns')
|
|
12
11
|
|
|
@@ -16,12 +15,7 @@ const clearDropdownKey = untypedKey()
|
|
|
16
15
|
* Abstract base class for dropdown parts.
|
|
17
16
|
* Subclasses must implement the `renderContent()` method to render the dropdown content.
|
|
18
17
|
*/
|
|
19
|
-
export abstract class Dropdown<
|
|
20
|
-
TState,
|
|
21
|
-
TThemeType extends ThemeType,
|
|
22
|
-
TApp extends TerrierApp<TThemeType, TApp, TTheme>,
|
|
23
|
-
TTheme extends Theme<TThemeType>
|
|
24
|
-
> extends TerrierPart<TState, TThemeType, TApp, TTheme> {
|
|
18
|
+
export abstract class Dropdown<TState> extends TerrierPart<TState> {
|
|
25
19
|
|
|
26
20
|
parentPart?: StatelessPart
|
|
27
21
|
|
|
@@ -29,12 +23,20 @@ export abstract class Dropdown<
|
|
|
29
23
|
return ['tt-dropdown', ...super.parentClasses]
|
|
30
24
|
}
|
|
31
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Override and return true to have the dropdown close when the user clicks anywhere outside of it.
|
|
28
|
+
*/
|
|
29
|
+
get autoClose(): boolean {
|
|
30
|
+
return false
|
|
31
|
+
}
|
|
32
|
+
|
|
32
33
|
// the computed absolute position of the
|
|
33
34
|
left = 0
|
|
34
35
|
top = 0
|
|
35
36
|
|
|
36
37
|
async init() {
|
|
37
|
-
this.onClick(clearDropdownKey,
|
|
38
|
+
this.onClick(clearDropdownKey, m => {
|
|
39
|
+
log.info("Clearing dropdown", m)
|
|
38
40
|
this.clear()
|
|
39
41
|
})
|
|
40
42
|
}
|
|
@@ -44,11 +46,15 @@ export abstract class Dropdown<
|
|
|
44
46
|
*/
|
|
45
47
|
clear() {
|
|
46
48
|
log.info("Clearing dropdown")
|
|
47
|
-
this.app.
|
|
49
|
+
this.app.removeDropdown(this.state)
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
render(parent: PartTag) {
|
|
51
|
-
|
|
53
|
+
if (this.autoClose) {
|
|
54
|
+
parent.div('.tt-dropdown-backdrop')
|
|
55
|
+
.emitClick(clearDropdownKey)
|
|
56
|
+
}
|
|
57
|
+
parent.div('.tt-dropdown-content', content => {
|
|
52
58
|
this.renderContent(content)
|
|
53
59
|
})
|
|
54
60
|
}
|
|
@@ -71,7 +77,7 @@ export abstract class Dropdown<
|
|
|
71
77
|
}
|
|
72
78
|
|
|
73
79
|
update(_elem: HTMLElement) {
|
|
74
|
-
const content = _elem.querySelector('.dropdown-content')
|
|
80
|
+
const content = _elem.querySelector('.tt-dropdown-content')
|
|
75
81
|
if (this.anchorTarget && content) {
|
|
76
82
|
log.info(`Anchoring dropdown`, content, this.anchorTarget)
|
|
77
83
|
Overlays.anchorElement(content as HTMLElement, this.anchorTarget)
|
|
@@ -84,12 +90,11 @@ export abstract class Dropdown<
|
|
|
84
90
|
/**
|
|
85
91
|
* A concrete dropdown part that shows a list of actions.
|
|
86
92
|
*/
|
|
87
|
-
export class ActionsDropdown<
|
|
88
|
-
TThemeType extends ThemeType,
|
|
89
|
-
TApp extends TerrierApp<TThemeType, TApp, TTheme>,
|
|
90
|
-
TTheme extends Theme<TThemeType>
|
|
91
|
-
> extends Dropdown<Array<Action<TThemeType>>, TThemeType, TApp, TTheme> {
|
|
93
|
+
export class ActionsDropdown extends Dropdown<Array<Action>> {
|
|
92
94
|
|
|
95
|
+
get autoClose(): boolean {
|
|
96
|
+
return true
|
|
97
|
+
}
|
|
93
98
|
|
|
94
99
|
get parentClasses(): Array<string> {
|
|
95
100
|
return ['tt-actions-dropdown', ...super.parentClasses]
|
|
@@ -101,7 +106,7 @@ export class ActionsDropdown<
|
|
|
101
106
|
const keys = unique(this.state.map(action => action.click?.key).filter(Objects.notNull))
|
|
102
107
|
for (const key of keys) {
|
|
103
108
|
this.onClick(key, m => {
|
|
104
|
-
this.
|
|
109
|
+
this.clear()
|
|
105
110
|
log.info(`Re-emitting ${key.id} message`, m, this.parentPart)
|
|
106
111
|
if (this.parentPart) {
|
|
107
112
|
this.parentPart.emit('click', key, m.event, m.data)
|
package/forms.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {SelectOptions} from "tuff-core/forms"
|
|
2
|
+
import {strings} from "tuff-core"
|
|
3
|
+
|
|
4
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
// Options
|
|
6
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Computes a `SelectOptions` array by titleizing the values in a plain string array.
|
|
10
|
+
* @param opts
|
|
11
|
+
*/
|
|
12
|
+
function titleizeOptions(opts: string[], blank?: string): SelectOptions {
|
|
13
|
+
const out = opts.map(c => {
|
|
14
|
+
return {value: c, title: strings.titleize(c)}
|
|
15
|
+
})
|
|
16
|
+
if (blank != undefined) { // don't test length, allow it to be a blank string
|
|
17
|
+
out.unshift({title: blank, value: ''})
|
|
18
|
+
}
|
|
19
|
+
return out
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
24
|
+
// Export
|
|
25
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
26
|
+
|
|
27
|
+
const Forms = {
|
|
28
|
+
titleizeOptions
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default Forms
|
|
32
|
+
|
|
33
|
+
|
package/fragments.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {PartTag} from "tuff-core/parts"
|
|
2
2
|
import {AnchorTagAttrs, HtmlParentTag} from "tuff-core/html"
|
|
3
|
-
import Theme, {Action,
|
|
4
|
-
import {ActionLevel, PanelActions} from "./parts"
|
|
3
|
+
import Theme, {Action, ColorName, IconName, Packet} from "./theme"
|
|
4
|
+
import {ActionLevel, PanelActions} from "./parts/content-part"
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Base class for Panel and Card fragment builders.
|
|
8
8
|
*/
|
|
9
|
-
abstract class ContentFragment
|
|
10
|
-
protected constructor(readonly prefix: string, readonly theme: Theme
|
|
11
|
-
|
|
9
|
+
abstract class ContentFragment {
|
|
10
|
+
protected constructor(readonly prefix: string, readonly theme: Theme) {
|
|
11
|
+
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
protected _title?: string
|
|
@@ -17,18 +17,18 @@ abstract class ContentFragment<TT extends ThemeType> {
|
|
|
17
17
|
* @param t the title
|
|
18
18
|
* @param icon the optional icon
|
|
19
19
|
*/
|
|
20
|
-
title(t: string, icon?:
|
|
20
|
+
title(t: string, icon?: IconName) {
|
|
21
21
|
this._title = t
|
|
22
22
|
this._icon = icon
|
|
23
23
|
return this
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
protected _icon?:
|
|
26
|
+
protected _icon?: IconName
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* @param i the panel icon
|
|
30
30
|
*/
|
|
31
|
-
icon(i:
|
|
31
|
+
icon(i: IconName) {
|
|
32
32
|
this._icon = i
|
|
33
33
|
return this
|
|
34
34
|
}
|
|
@@ -46,17 +46,17 @@ abstract class ContentFragment<TT extends ThemeType> {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
export class PanelFragment
|
|
50
|
-
constructor(theme: Theme
|
|
49
|
+
export class PanelFragment extends ContentFragment {
|
|
50
|
+
constructor(theme: Theme) {
|
|
51
51
|
super('tt-panel', theme)
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/// Actions
|
|
55
55
|
|
|
56
56
|
actions = {
|
|
57
|
-
primary: Array<Action
|
|
58
|
-
secondary: Array<Action
|
|
59
|
-
tertiary: Array<Action
|
|
57
|
+
primary: Array<Action>(),
|
|
58
|
+
secondary: Array<Action>(),
|
|
59
|
+
tertiary: Array<Action>()
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
/**
|
|
@@ -64,7 +64,7 @@ export class PanelFragment<TT extends ThemeType> extends ContentFragment<TT> {
|
|
|
64
64
|
* @param action the action to add
|
|
65
65
|
* @param level whether it's a primary, secondary, or tertiary action
|
|
66
66
|
*/
|
|
67
|
-
addAction(action: Action
|
|
67
|
+
addAction(action: Action, level: ActionLevel = 'primary') {
|
|
68
68
|
this.actions[level].push(action)
|
|
69
69
|
return this
|
|
70
70
|
}
|
|
@@ -102,16 +102,18 @@ export class PanelFragment<TT extends ThemeType> extends ContentFragment<TT> {
|
|
|
102
102
|
* Render the primary and secondary actions to the bottom of a panel
|
|
103
103
|
* @param panel the .panel container
|
|
104
104
|
* @param actions the actions
|
|
105
|
+
* @param theme the theme with which to render actions
|
|
105
106
|
*/
|
|
106
|
-
function panelActions
|
|
107
|
+
function panelActions(panel: PartTag, actions: PanelActions, theme: Theme) {
|
|
107
108
|
if (actions.primary.length || actions.secondary.length) {
|
|
108
109
|
panel.div('.panel-actions', actionsContainer => {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
for (const level of ['secondary', 'primary'] as const) {
|
|
111
|
+
const levelActions = actions[level]
|
|
112
|
+
if (!levelActions?.length) continue;
|
|
113
|
+
actionsContainer.div(`.${level}-actions`, container => {
|
|
114
|
+
theme.renderActions(container, levelActions, { iconColor: 'white', defaultClass: level })
|
|
115
|
+
})
|
|
116
|
+
}
|
|
115
117
|
})
|
|
116
118
|
}
|
|
117
119
|
}
|
|
@@ -120,8 +122,8 @@ function panelActions<TT extends ThemeType>(panel: PartTag, actions: PanelAction
|
|
|
120
122
|
/**
|
|
121
123
|
* Cards are like panels except they don't have any actions and are themselves an anchor.
|
|
122
124
|
*/
|
|
123
|
-
class CardFragment
|
|
124
|
-
constructor(theme: Theme
|
|
125
|
+
class CardFragment extends ContentFragment {
|
|
126
|
+
constructor(theme: Theme) {
|
|
125
127
|
super('tt-card', theme)
|
|
126
128
|
}
|
|
127
129
|
|
|
@@ -162,15 +164,15 @@ class CardFragment<TT extends ThemeType> extends ContentFragment<TT> {
|
|
|
162
164
|
}
|
|
163
165
|
|
|
164
166
|
|
|
165
|
-
class LabeledValueFragment
|
|
167
|
+
class LabeledValueFragment extends ContentFragment {
|
|
166
168
|
|
|
167
|
-
constructor(theme: Theme
|
|
169
|
+
constructor(theme: Theme) {
|
|
168
170
|
super('tt-labeled-value', theme)
|
|
169
171
|
}
|
|
170
172
|
|
|
171
173
|
private _value?: string
|
|
172
|
-
private _valueIcon?:
|
|
173
|
-
private _valueIconColor?:
|
|
174
|
+
private _valueIcon?: IconName
|
|
175
|
+
private _valueIconColor?: ColorName | null
|
|
174
176
|
private _valueClass?: string[]
|
|
175
177
|
|
|
176
178
|
private _href?: string
|
|
@@ -180,7 +182,7 @@ class LabeledValueFragment<TT extends ThemeType> extends ContentFragment<TT> {
|
|
|
180
182
|
|
|
181
183
|
private _tooltip?: string
|
|
182
184
|
|
|
183
|
-
value(value: string, icon?:
|
|
185
|
+
value(value: string, icon?: IconName, iconColor?: ColorName | null) {
|
|
184
186
|
this._value = value
|
|
185
187
|
this._valueIcon = icon
|
|
186
188
|
this._valueIconColor = iconColor
|
|
@@ -256,10 +258,10 @@ type ListValueDefinition = {
|
|
|
256
258
|
tooltip?: string
|
|
257
259
|
}
|
|
258
260
|
|
|
259
|
-
class LabeledListFragment
|
|
261
|
+
class LabeledListFragment extends ContentFragment {
|
|
260
262
|
private _values?: ListValueDefinition[]
|
|
261
263
|
|
|
262
|
-
constructor(theme: Theme
|
|
264
|
+
constructor(theme: Theme) {
|
|
263
265
|
super('tt-labeled-list', theme)
|
|
264
266
|
}
|
|
265
267
|
|
|
@@ -305,7 +307,7 @@ class LabeledListFragment<TT extends ThemeType> extends ContentFragment<TT> {
|
|
|
305
307
|
* Creates a new card fragment builder.
|
|
306
308
|
* Make sure to call `render()` in order to render it to a parent tag.
|
|
307
309
|
*/
|
|
308
|
-
function card
|
|
310
|
+
function card(theme: Theme) {
|
|
309
311
|
return new CardFragment(theme)
|
|
310
312
|
}
|
|
311
313
|
|
|
@@ -314,7 +316,7 @@ function card<TT extends ThemeType>(theme: Theme<TT>) {
|
|
|
314
316
|
* Creates a new panel fragment builder.
|
|
315
317
|
* Make sure to call `render()` in order to render it to a parent tag.
|
|
316
318
|
*/
|
|
317
|
-
function panel
|
|
319
|
+
function panel(theme: Theme) {
|
|
318
320
|
return new PanelFragment(theme)
|
|
319
321
|
}
|
|
320
322
|
|
|
@@ -322,18 +324,18 @@ function panel<TT extends ThemeType>(theme: Theme<TT>) {
|
|
|
322
324
|
* Creates a new labeled value fragment builder.
|
|
323
325
|
* Make sure to call `render()` in order to render it to a parent tag.
|
|
324
326
|
*/
|
|
325
|
-
function labeledValue
|
|
327
|
+
function labeledValue(theme: Theme) {
|
|
326
328
|
return new LabeledValueFragment(theme)
|
|
327
329
|
}
|
|
328
330
|
|
|
329
|
-
function labeledList
|
|
331
|
+
function labeledList(theme: Theme) {
|
|
330
332
|
return new LabeledListFragment(theme)
|
|
331
333
|
}
|
|
332
334
|
|
|
333
335
|
/**
|
|
334
336
|
* Create a new button in the parent.
|
|
335
337
|
*/
|
|
336
|
-
function button
|
|
338
|
+
function button(parent: PartTag, theme: Theme, title?: string, icon?: IconName, iconColor: ColorName | null = null) {
|
|
337
339
|
return parent.a('.tt-button', button => {
|
|
338
340
|
if (icon) theme.renderIcon(button, icon, iconColor)
|
|
339
341
|
if (title?.length) button.div('.title', {text: title})
|
|
@@ -344,7 +346,7 @@ function button<TT extends ThemeType>(parent: PartTag, theme: Theme<TT>, title?:
|
|
|
344
346
|
* Create a new simple value display in the parent.
|
|
345
347
|
* This is just some text with an optional icon that doesn't have a separate label.
|
|
346
348
|
*/
|
|
347
|
-
function simpleValue
|
|
349
|
+
function simpleValue(parent: PartTag, theme: Theme, title: string, icon?: IconName, iconColor: ColorName | null = 'link') {
|
|
348
350
|
return parent.div('.tt-simple-value.shrink', button => {
|
|
349
351
|
if (icon) theme.renderIcon(button, icon, iconColor)
|
|
350
352
|
button.div('.title', {text: title})
|
|
@@ -354,7 +356,7 @@ function simpleValue<TT extends ThemeType>(parent: PartTag, theme: Theme<TT>, ti
|
|
|
354
356
|
/**
|
|
355
357
|
* Helper to create a heading with an optional icon.
|
|
356
358
|
*/
|
|
357
|
-
function simpleHeading
|
|
359
|
+
function simpleHeading(parent: PartTag, theme: Theme, title: string, icon?: IconName) {
|
|
358
360
|
return parent.h3('.shrink', heading => {
|
|
359
361
|
if (icon) {
|
|
360
362
|
theme.renderIcon(heading, icon, 'link')
|