@operato/shell 2.0.0-alpha.8 → 2.0.0-alpha.80

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +151 -0
  2. package/demo/index.html +14 -3
  3. package/dist/src/actions/busy.js.map +1 -1
  4. package/dist/src/actions/route.d.ts +3 -3
  5. package/dist/src/actions/route.js +5 -5
  6. package/dist/src/actions/route.js.map +1 -1
  7. package/dist/src/app/app-style.js +12 -4
  8. package/dist/src/app/app-style.js.map +1 -1
  9. package/dist/src/app/app.d.ts +10 -5
  10. package/dist/src/app/app.js +27 -15
  11. package/dist/src/app/app.js.map +1 -1
  12. package/dist/src/app/pages/page-404.d.ts +1 -1
  13. package/dist/src/app/pages/page-404.js +5 -5
  14. package/dist/src/app/pages/page-404.js.map +1 -1
  15. package/dist/src/custom-alert.d.ts +23 -0
  16. package/dist/src/custom-alert.js +26 -0
  17. package/dist/src/custom-alert.js.map +1 -0
  18. package/dist/src/entries/public/home.d.ts +2 -3
  19. package/dist/src/entries/public/home.js +17 -16
  20. package/dist/src/entries/public/home.js.map +1 -1
  21. package/dist/src/index.d.ts +1 -0
  22. package/dist/src/index.js +1 -0
  23. package/dist/src/index.js.map +1 -1
  24. package/dist/src/store.js +8 -0
  25. package/dist/src/store.js.map +1 -1
  26. package/dist/stories/app.stories.d.ts +22 -0
  27. package/dist/stories/app.stories.js +38 -0
  28. package/dist/stories/app.stories.js.map +1 -0
  29. package/dist/tsconfig.tsbuildinfo +1 -1
  30. package/package.json +19 -19
  31. package/src/actions/busy.ts +1 -1
  32. package/src/actions/route.ts +5 -5
  33. package/src/app/app-style.ts +12 -4
  34. package/src/app/app.ts +49 -16
  35. package/src/app/pages/page-404.ts +5 -5
  36. package/src/custom-alert.ts +43 -0
  37. package/src/entries/public/home.ts +17 -16
  38. package/src/index.ts +1 -0
  39. package/src/store.ts +9 -0
  40. package/stories/app.stories.ts +51 -0
  41. package/themes/app-theme.css +145 -0
  42. package/yarn-error.log +4 -5
package/src/app/app.ts CHANGED
@@ -23,7 +23,21 @@ export class ThingsApp extends connect(store)(LitElement) {
23
23
 
24
24
  static moduleInitialized: MODULES_STATE = MODULES_STATE.NOT_INITIALIZED
25
25
  static modules: Array<any> = []
26
- static pages: { [path: string]: string } = {}
26
+
27
+ /*
28
+ 모든 모듈의 routes 리스트가 수집될 때까지, routeToPage(..) 를 hold 시키기 위해서 ThingsApp.pages를 Promise로 정의한다.
29
+ */
30
+ static pagesResolver: (
31
+ value:
32
+ | {
33
+ [path: string]: string
34
+ }
35
+ | PromiseLike<{
36
+ [path: string]: string
37
+ }>
38
+ ) => void
39
+ static pages: Promise<{ [path: string]: string }>
40
+
27
41
  static callbacks: Array<any> = []
28
42
  static contextPath?: string
29
43
 
@@ -86,13 +100,13 @@ export class ThingsApp extends connect(store)(LitElement) {
86
100
  ).then(module => {
87
101
  var modules: {
88
102
  name: string
89
- bootstrap: any
103
+ bootstrap: (m?: any /* self */) => void
90
104
  }[] = module.modules
91
105
 
92
106
  /* lifecycle - bootstrapping */
93
107
  modules.forEach(async (m, idx) => {
94
108
  try {
95
- m.bootstrap && (await m.bootstrap())
109
+ m.bootstrap && (await m.bootstrap(m))
96
110
  } catch (e) {
97
111
  console.error(`[${idx} BOOTSTRAP ERROR -${m.name}]`, e)
98
112
  }
@@ -114,7 +128,13 @@ export class ThingsApp extends connect(store)(LitElement) {
114
128
  var { contextPath } = getPathInfo(pathname)
115
129
 
116
130
  /* 페이지를 나가기 전에 옮기지 않도록 개입할 기회를 준다 */
117
- if (lastPathName && lastPathName != pathname && this.activePage && !(await this.activePage.canDeactivate())) {
131
+ if (
132
+ lastPathName &&
133
+ lastPathName != pathname &&
134
+ this.activePage &&
135
+ this.activePage.canDeactivate &&
136
+ !(await this.activePage.canDeactivate())
137
+ ) {
118
138
  history.back()
119
139
  return
120
140
  }
@@ -146,7 +166,7 @@ export class ThingsApp extends connect(store)(LitElement) {
146
166
  super.disconnectedCallback()
147
167
  }
148
168
 
149
- routeToPage() {
169
+ async routeToPage() {
150
170
  const activePages = this.renderRoot.querySelectorAll('main > .page[active]')
151
171
  activePages.forEach(page => {
152
172
  page.removeAttribute('active')
@@ -156,7 +176,7 @@ export class ThingsApp extends connect(store)(LitElement) {
156
176
 
157
177
  if (!this.activePage) {
158
178
  /* 해당 route에 연결된 page가 없는 경우에 main 섹션에 해당 element를 추가해준다. */
159
- const tagname = ThingsApp.pages[this.page!]
179
+ const tagname = (await ThingsApp.pages)[this.page!]
160
180
  if (tagname) {
161
181
  const el = document.createElement(tagname) as PageView
162
182
  el.setAttribute('class', 'page')
@@ -219,19 +239,32 @@ export class ThingsApp extends connect(store)(LitElement) {
219
239
  ThingsApp.callbacks = state.route.callbacks
220
240
  }
221
241
 
222
- static registerPages() {
242
+ static async registerPages() {
243
+ ThingsApp.pages = new Promise<{ [path: string]: string }>(resolve => (ThingsApp.pagesResolver = resolve))
244
+
223
245
  var reversedModules = [...ThingsApp.modules].reverse()
224
- ThingsApp.pages = {}
246
+ const pages: { [path: string]: string } = {}
225
247
 
226
248
  /* 모듈 참조 순서 역순으로 page를 추가한다. (for overidable) */
227
- reversedModules.forEach(m => {
228
- m.routes &&
229
- m.routes.forEach((route: any) => {
230
- if (!ThingsApp.pages[route.page]) {
231
- ThingsApp.pages[route.page] = route.tagname
232
- }
233
- })
234
- })
249
+ for (const m of reversedModules) {
250
+ if (!m.routes) {
251
+ continue
252
+ }
253
+
254
+ /*
255
+ 각 모듈의 routes가 모두 완성될 때까지 ThingsApp.pages 구성을 지연한다.
256
+ 각 모듈의 routes를 동적으로도 구성할 수 있도록 하기 위해서이다.
257
+ */
258
+ const routes = await m.routes
259
+
260
+ routes.forEach((route: any) => {
261
+ if (!pages[route.page]) {
262
+ pages[route.page] = route.tagname
263
+ }
264
+ })
265
+ }
266
+
267
+ ThingsApp.pagesResolver(pages)
235
268
  }
236
269
 
237
270
  setBase() {
@@ -17,8 +17,8 @@ export class Page404 extends PageView {
17
17
  text-align: center;
18
18
  color: var(--secondary-color);
19
19
  }
20
- mwc-icon {
21
- --mdc-icon-size: 120px;
20
+ md-icon {
21
+ --md-icon-size: 120px;
22
22
  color: var(--status-danger-color);
23
23
  text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.1);
24
24
  }
@@ -28,9 +28,9 @@ export class Page404 extends PageView {
28
28
  text-transform: capitalize;
29
29
  }
30
30
  @media only screen and (max-width: 460px) {
31
- mwc-icon {
31
+ md-icon {
32
32
  padding-top: 25%;
33
- --mdc-icon-size: 90px;
33
+ --md-icon-size: 90px;
34
34
  }
35
35
  h2 {
36
36
  font-size: 2em;
@@ -47,7 +47,7 @@ export class Page404 extends PageView {
47
47
  render() {
48
48
  return html`
49
49
  <section>
50
- <mwc-icon>error_outline</mwc-icon>
50
+ <md-icon>error_outline</md-icon>
51
51
  <h2>page not found!</h2>
52
52
  The page you requested cannot be found.
53
53
  </section>
@@ -0,0 +1,43 @@
1
+ import { OxPrompt } from '@operato/popup'
2
+
3
+ const TYPES_ICON: { [type: string]: string } = {
4
+ success: 'verified',
5
+ error: 'error',
6
+ warning: 'warning',
7
+ info: 'info',
8
+ question: 'question_mark'
9
+ }
10
+
11
+ export async function CustomAlert({
12
+ type,
13
+ icon,
14
+ title,
15
+ text,
16
+ confirmButton,
17
+ cancelButton,
18
+ callback
19
+ }: {
20
+ type?: 'info' | 'success' | 'error' | 'warning' | 'question'
21
+ icon?: string
22
+ title?: string
23
+ text?: string
24
+ confirmButton?: { color?: string; text: string }
25
+ cancelButton?: { color?: string; text: string }
26
+ callback?: (val: { isConfirmed: boolean; isDismissed: boolean; value: boolean }) => any
27
+ }) {
28
+ const result = await OxPrompt.open({
29
+ type: type || 'info',
30
+ icon: (icon && TYPES_ICON[icon]) || icon,
31
+ title,
32
+ text,
33
+ confirmButton,
34
+ cancelButton
35
+ })
36
+
37
+ const val = { isConfirmed: result, isDismissed: !result, value: result }
38
+ if (callback && typeof callback === 'function') {
39
+ callback(val)
40
+ } else {
41
+ return val
42
+ }
43
+ }
@@ -1,5 +1,4 @@
1
- import '@material/mwc-icon-button'
2
- import '@material/mwc-button'
1
+ import '@material/web/icon/icon.js'
3
2
 
4
3
  import { css, html, LitElement } from 'lit'
5
4
  import { customElement } from 'lit/decorators.js'
@@ -13,7 +12,7 @@ export class HomePage extends LitElement {
13
12
  display: block;
14
13
  position: relative;
15
14
 
16
- --mdc-theme-primary: white;
15
+ --md-theme-primary: white;
17
16
  }
18
17
 
19
18
  [home] {
@@ -30,17 +29,19 @@ export class HomePage extends LitElement {
30
29
  color: #fff;
31
30
  text-align: center;
32
31
  font-size: 20px;
33
- }
34
- [message] strong {
35
- display: block;
36
- font-size: 2.5rem;
37
- }
38
- [message] img {
39
- width: 450px;
40
- max-width: 90%;
41
- display: block;
42
- margin: auto;
43
- margin-top: 20px;
32
+
33
+ strong {
34
+ display: block;
35
+ font-size: 2.5rem;
36
+ }
37
+
38
+ img {
39
+ width: 450px;
40
+ max-width: 90%;
41
+ display: block;
42
+ margin: auto;
43
+ margin-top: 20px;
44
+ }
44
45
  }
45
46
 
46
47
  @media screen and (max-width: 460px) {
@@ -64,10 +65,10 @@ export class HomePage extends LitElement {
64
65
  }
65
66
 
66
67
  render() {
67
- var { icon, title, description } = this.applicationMeta
68
+ var { title, description } = this.applicationMeta
68
69
 
69
70
  return html`
70
- <mwc-icon-button home icon="home" @click=${() => (window.location.href = '/')}></mwc-icon-button>
71
+ <md-icon home @click=${() => (window.location.href = '/')}>home</md-icon>
71
72
 
72
73
  <div message>
73
74
  <strong>${title}</strong>
package/src/index.ts CHANGED
@@ -3,3 +3,4 @@ export * from './store'
3
3
  export * from './actions'
4
4
  export * from './app/pages/page-view'
5
5
  export * from './object-store'
6
+ export * from './custom-alert'
package/src/store.ts CHANGED
@@ -14,6 +14,15 @@ declare global {
14
14
  // See https://github.com/zalmoxisus/redux-devtools-extension for more information.
15
15
  const devCompose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
16
16
 
17
+ // Only for providing test environment - combineReducers 에서 process.env.NODE_ENV를 접근하기 때문에.
18
+ if (typeof window.process == 'undefined') {
19
+ window.process = {
20
+ env: {
21
+ NODE_ENV: JSON.stringify('development')
22
+ }
23
+ } as any
24
+ }
25
+
17
26
  export const store: Store<unknown, Action<any>> & LazyStore = createStore(
18
27
  state => state,
19
28
  devCompose(lazyReducerEnhancer(combineReducers), applyMiddleware(thunk))
@@ -0,0 +1,51 @@
1
+ import '@material/web/icon/icon.js'
2
+
3
+ import { css, html, render, TemplateResult } from 'lit'
4
+ import '../src/app/app.js'
5
+
6
+ export default {
7
+ title: 'things-app',
8
+ component: 'things-app',
9
+ argTypes: {
10
+ label: { control: 'string' }
11
+ }
12
+ }
13
+
14
+ interface Story<T> {
15
+ (args: T): TemplateResult
16
+ args?: Partial<T>
17
+ argTypes?: Record<string, unknown>
18
+ }
19
+
20
+ interface ArgTypes {
21
+ label?: string
22
+ }
23
+
24
+ const Template: Story<ArgTypes> = ({ label = '' }: ArgTypes) => html`
25
+ <link href="/themes/app-theme.css" rel="stylesheet" />
26
+ <link
27
+ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL@20..48,100..700,0..1"
28
+ rel="stylesheet"
29
+ />
30
+ <link
31
+ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL@20..48,100..700,0..1"
32
+ rel="stylesheet"
33
+ />
34
+ <link
35
+ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL@20..48,100..700,0..1"
36
+ rel="stylesheet"
37
+ />
38
+
39
+ <style>
40
+ body {
41
+ background-color: white;
42
+ }
43
+ </style>
44
+
45
+ <things-app></things-app>
46
+ `
47
+
48
+ export const Regular = Template.bind({})
49
+ Regular.args = {
50
+ label: 'common header styles'
51
+ }
@@ -0,0 +1,145 @@
1
+ body {
2
+ /* theme color */
3
+ --primary-color-rgb: 130, 105, 96;
4
+ --primary-color: rgb(var(--primary-color-rgb));
5
+ --secondary-color-rgb: 78, 78, 90;
6
+ --secondary-color: rgb(var(--secondary-color-rgb));
7
+ --focus-color: var(--theme-white-color);
8
+ --primary-background-color: var(--secondary-color);
9
+ --secondary-background-color: #283644;
10
+ --main-section-background-color: #f5f2ee;
11
+ --theme-white-color: #fff;
12
+ --theme-black-color: rgba(0, 0, 0, 0.9);
13
+
14
+ --focus-background-color: var(--primary-color);
15
+ --primary-text-color: #3c3938;
16
+ --secondary-text-color: var(--primary-color);
17
+
18
+ --opacity-dark-color: rgba(0, 0, 0, 0.4);
19
+ --opacity-light-color: rgba(255, 255, 255, 0.8);
20
+
21
+ /* status color */
22
+ --status-success-color: #35a24a;
23
+ --status-warning-color: #ee8d03;
24
+ --status-danger-color: #d14946;
25
+ --status-info-color: #398ace;
26
+
27
+ /* common style */
28
+ --border-radius: 4px;
29
+ --border-dark-color: 1px solid rgba(0, 0, 0, 0.15);
30
+ --border-light-color: 1px solid rgba(255, 255, 255, 0.3);
31
+
32
+ --box-shadow: 2px 2px 3px 0px rgba(0, 0, 0, 0.1);
33
+
34
+ --theme-font: 'Noto', Helvetica;
35
+
36
+ --margin-default: 9px;
37
+ --margin-narrow: 4px;
38
+ --margin-wide: 15px;
39
+ --padding-default: var(--margin-default);
40
+ --padding-narrow: var(--margin-narrow);
41
+ --padding-wide: var(--margin-wide);
42
+
43
+ --scrollbar-thumb-color: rgba(57, 78, 100, 0.5);
44
+ --scrollbar-thumb-hover-color: var(--primary-color);
45
+
46
+ --fontsize-default: 14px;
47
+ --fontsize-small: 13px;
48
+ --fontsize-large: 16px;
49
+
50
+ /* app layout style */
51
+ --app-grid-template-area: 'header header header' 'nav main aside' 'nav footer aside';
52
+
53
+ /* title & description style */
54
+ --title-margin: var(--margin-narrow) 0;
55
+ --title-font: bold 24px var(--theme-font);
56
+ --title-text-color: var(--secondary-color);
57
+ --title-font-mobile: bold 20px var(--theme-font);
58
+
59
+ --page-description-margin: var(--margin-narrow) 0 var(--margin-wide) 0;
60
+ --page-description-font: normal var(--fontsize-default) / 1.2rem var(--theme-font);
61
+ --page-description-color: var(--secondary-text-color);
62
+
63
+ --subtitle-padding: 12px 5px 3px 5px;
64
+ --subtitle-font: bold 18px var(--theme-font);
65
+ --subtitle-text-color: var(--primary-color);
66
+ --subtitle-border-bottom: 1px solid var(--primary-color);
67
+
68
+ /* icon style */
69
+ --icon-tiny-size: 24px;
70
+ --icon-default-size: 36px;
71
+ --icon-big-size: 48px;
72
+ --icon-default-color: var(--theme-white-color);
73
+
74
+ /* material design component themes */
75
+ --mdc-theme-on-primary: var(--theme-white-color);
76
+ --mdc-theme-primary: var(--secondary-text-color);
77
+ --mdc-theme-on-secondary: var(--theme-white-color);
78
+ --mdc-theme-secondary: var(--primary-color);
79
+ --mdc-button-outline-color: var(--primary-color);
80
+ --mdc-danger-button-primary-color: var(--status-danger-color);
81
+ --mdc-danger-button-outline-color: var(--status-danger-color);
82
+ --mdc-button-outline-width: 1px;
83
+ --mdc-button-horizontal-padding: 16px;
84
+
85
+ /* button style */
86
+ --button-background-color: #fafbfc;
87
+ --button-background-focus-color: var(--primary-color);
88
+ --button-border: var(--border-dark-color);
89
+ --button-border-radius: var(--border-radius);
90
+ --button-margin: var(--margin-default) var(--margin-default) var(--margin-default) 0;
91
+ --button-padding: var(--padding-default);
92
+ --button-color: var(--secondary-color);
93
+ --button-font: normal 15px var(--theme-font);
94
+ --button-text-transform: capitalize;
95
+ --button-active-box-shadow: 1px 1px 1px 0px rgba(0, 0, 0, 0.2);
96
+ --button-activ-border: 1px solid var(--primary-color);
97
+
98
+ --button-primary-background-color: var(--primary-color);
99
+ --button-primary-active-background-color: var(--status-success-color);
100
+ --button-primary-padding: var(--margin-default) var(--margin-wide);
101
+ --button-primary-color: var(--theme-white-color);
102
+ --button-primary-font: bold 16px var(--theme-font);
103
+
104
+ /* table style */
105
+ --th-padding: var(--padding-default);
106
+ --th-border-top: 2px solid var(--secondary-color);
107
+ --th-text-transform: capitalize;
108
+ --th-font: bold var(--fontsize-small) var(--theme-font);
109
+ --th-color: rgba(var(--secondary-color-rgb), 0.8);
110
+
111
+ --tr-background-color: var(--theme-white-color);
112
+ --tr-background-odd-color: rgba(255, 255, 255, 0.4);
113
+ --tr-background-hover-color: #e1f5fe;
114
+ --td-border-line: 1px solid rgba(0, 0, 0, 0.05);
115
+ --td-border-bottom: 1px solid rgba(0, 0, 0, 0.09);
116
+ --td-padding: var(--padding-default);
117
+ --td-font: normal 13px var(--theme-font);
118
+ --td-color: var(--secondary-color);
119
+
120
+ --label-cell-background-color: #f6f6f6; /* th or td common background color */
121
+
122
+ /* form style */
123
+ --label-font: normal var(--fontsize-default) var(--theme-font);
124
+ --label-color: var(--secondary-color);
125
+ --label-text-transform: capitalize;
126
+ --input-margin: var(--margin-narrow) 0;
127
+ --input-padding: var(--padding-default);
128
+ --input-min-width: 200px;
129
+ --input-font: normal var(--fontsize-default) var(--theme-font);
130
+ --input-hint-font: normal var(--fontsize-small) var(--theme-font);
131
+ --input-hint-color: #666;
132
+ --input-container-max-width: 900px;
133
+ --fieldset-margin: var(--padding-wide) 0;
134
+ --fieldset-padding: 0 var(--padding-wide) var(--padding-wide) var(--padding-wide);
135
+ --legend-padding: var(--padding-default) 0;
136
+ --legend-color: var(--secondary-text-color);
137
+ --legend-font: bold 16px var(--theme-font);
138
+ }
139
+
140
+ @media only screen and (max-width: 460px) {
141
+ body {
142
+ /* subtitle style */
143
+ --subtitle-margin: 0;
144
+ }
145
+ }
package/yarn-error.log CHANGED
@@ -85,8 +85,7 @@ npm manifest:
85
85
  },
86
86
  "dependencies": {
87
87
  "@material/mwc-button": "^0.27.0",
88
- "@material/mwc-icon": "^0.27.0",
89
- "@material/mwc-icon-button": "^0.27.0",
88
+ "@material/mwc-icon-button": "^0.27.0",
90
89
  "@operato/graphql": "^1.2.6",
91
90
  "@operato/styles": "^1.2.0",
92
91
  "@operato/utils": "^1.2.4",
@@ -109,10 +108,10 @@ npm manifest:
109
108
  "@web/test-runner": "^0.15.0",
110
109
  "concurrently": "^5.3.0",
111
110
  "eslint": "^7.32.0",
112
- "eslint-config-prettier": "^8.3.0",
113
- "husky": "^8.0.1",
111
+ "eslint-config-prettier": "^9.1.0",
112
+ "husky": "^9.0.11",
114
113
  "lint-staged": "^10.5.4",
115
- "prettier": "^2.4.1",
114
+ "prettier": "^3.2.5",
116
115
  "tslib": "^2.3.1",
117
116
  "typescript": "^4.8.4"
118
117
  },