@operato/shell 0.3.7

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 (62) hide show
  1. package/.editorconfig +29 -0
  2. package/.storybook/main.js +3 -0
  3. package/.storybook/server.mjs +8 -0
  4. package/@types/global/index.d.ts +1 -0
  5. package/CHANGELOG.md +235 -0
  6. package/LICENSE +21 -0
  7. package/README.md +75 -0
  8. package/demo/index.html +33 -0
  9. package/dist/src/actions/app.d.ts +11 -0
  10. package/dist/src/actions/app.js +12 -0
  11. package/dist/src/actions/app.js.map +1 -0
  12. package/dist/src/actions/index.d.ts +2 -0
  13. package/dist/src/actions/index.js +3 -0
  14. package/dist/src/actions/index.js.map +1 -0
  15. package/dist/src/actions/route.d.ts +26 -0
  16. package/dist/src/actions/route.js +76 -0
  17. package/dist/src/actions/route.js.map +1 -0
  18. package/dist/src/app/app-style.d.ts +1 -0
  19. package/dist/src/app/app-style.js +68 -0
  20. package/dist/src/app/app-style.js.map +1 -0
  21. package/dist/src/app/app.d.ts +1 -0
  22. package/dist/src/app/app.js +192 -0
  23. package/dist/src/app/app.js.map +1 -0
  24. package/dist/src/app/pages/page-404.d.ts +1 -0
  25. package/dist/src/app/pages/page-404.js +52 -0
  26. package/dist/src/app/pages/page-404.js.map +1 -0
  27. package/dist/src/app/pages/page-view.d.ts +16 -0
  28. package/dist/src/app/pages/page-view.js +131 -0
  29. package/dist/src/app/pages/page-view.js.map +1 -0
  30. package/dist/src/entries/public/home.d.ts +17 -0
  31. package/dist/src/entries/public/home.js +87 -0
  32. package/dist/src/entries/public/home.js.map +1 -0
  33. package/dist/src/index.d.ts +0 -0
  34. package/dist/src/index.js +2 -0
  35. package/dist/src/index.js.map +1 -0
  36. package/dist/src/reducers/app.d.ts +36 -0
  37. package/dist/src/reducers/app.js +36 -0
  38. package/dist/src/reducers/app.js.map +1 -0
  39. package/dist/src/reducers/route.d.ts +16 -0
  40. package/dist/src/reducers/route.js +57 -0
  41. package/dist/src/reducers/route.js.map +1 -0
  42. package/dist/src/store.d.ts +4 -0
  43. package/dist/src/store.js +16 -0
  44. package/dist/src/store.js.map +1 -0
  45. package/dist/tsconfig.tsbuildinfo +1 -0
  46. package/package.json +78 -0
  47. package/src/actions/app.ts +23 -0
  48. package/src/actions/index.ts +2 -0
  49. package/src/actions/route.ts +94 -0
  50. package/src/app/app-style.ts +68 -0
  51. package/src/app/app.ts +205 -0
  52. package/src/app/pages/page-404.ts +56 -0
  53. package/src/app/pages/page-view.ts +142 -0
  54. package/src/entries/public/home.ts +95 -0
  55. package/src/index.ts +0 -0
  56. package/src/module-importer.import +0 -0
  57. package/src/reducers/app.ts +48 -0
  58. package/src/reducers/route.ts +77 -0
  59. package/src/store.ts +26 -0
  60. package/tsconfig.json +23 -0
  61. package/web-dev-server.config.mjs +27 -0
  62. package/web-test-runner.config.mjs +41 -0
@@ -0,0 +1,56 @@
1
+ import { css, html } from 'lit'
2
+
3
+ import { PageView } from './page-view'
4
+
5
+ class Page404 extends PageView {
6
+ static styles = css`
7
+ :host {
8
+ display: block;
9
+ box-sizing: border-box;
10
+ background-color: var(--main-section-background-color);
11
+ --padding-wide: 15%;
12
+ }
13
+ section {
14
+ padding: var(--padding-wide) 0 0 0;
15
+ text-align: center;
16
+ color: var(--secondary-color);
17
+ }
18
+ mwc-icon {
19
+ --mdc-icon-size: 120px;
20
+ color: var(--status-danger-color);
21
+ text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.1);
22
+ }
23
+ h2 {
24
+ margin: 0 auto;
25
+ font-size: 2.5em;
26
+ text-transform: capitalize;
27
+ }
28
+ @media only screen and (max-width: 460px) {
29
+ mwc-icon {
30
+ padding-top: 25%;
31
+ --mdc-icon-size: 90px;
32
+ }
33
+ h2 {
34
+ font-size: 2em;
35
+ }
36
+ }
37
+ `
38
+
39
+ get context() {
40
+ return {
41
+ title: 'Page Not Found'
42
+ }
43
+ }
44
+
45
+ render() {
46
+ return html`
47
+ <section>
48
+ <mwc-icon>error_outline</mwc-icon>
49
+ <h2>page not found!</h2>
50
+ The page you requested cannot be found.
51
+ </section>
52
+ `
53
+ }
54
+ }
55
+
56
+ customElements.define('page-404', Page404)
@@ -0,0 +1,142 @@
1
+ import { LitElement, PropertyValues } from 'lit'
2
+ import { property } from 'lit/decorators.js'
3
+ import isEqual from 'lodash/isEqual'
4
+
5
+ import { UPDATE_CONTEXT } from '../../actions/route'
6
+ import { store } from '../../store'
7
+
8
+ function diff(after: any, before: any): any {
9
+ var changed = false
10
+ var changes: { [key: string]: any } = {}
11
+
12
+ Object.getOwnPropertyNames(after).forEach(function (key) {
13
+ let before_val = before[key]
14
+ let after_val = after[key]
15
+
16
+ if (!isEqual(before_val, after_val)) {
17
+ changes[key] = after_val
18
+ changed = true
19
+ }
20
+ })
21
+
22
+ return changed && changes
23
+ }
24
+
25
+ export class PageView extends LitElement {
26
+ // Only render this page if it's actually visible.
27
+ shouldUpdate(changes: PropertyValues<this>) {
28
+ var active = String(this.active) == 'true'
29
+ var { active: oldActive = false } = this._oldLifecycleInfo$ || {}
30
+
31
+ /*
32
+ * page lifecycle
33
+ * case 1. page가 새로 activate 되었다.
34
+ * case 2. page가 active 상태에서 lifecycle 정보가 바뀌었다.
35
+ **/
36
+ if (active) {
37
+ this.pageUpdate({
38
+ active
39
+ })
40
+ } else if (oldActive) {
41
+ this.pageUpdate({
42
+ active
43
+ })
44
+ }
45
+
46
+ return active
47
+ }
48
+
49
+ @property({ type: Boolean }) active: boolean = false
50
+ @property({ type: Object }) lifecycle: any
51
+ @property({ type: String, attribute: 'context-path' }) contextPath?: string
52
+
53
+ _oldLifecycleInfo$: any
54
+
55
+ /* lifecycle */
56
+ async pageUpdate(changes: any = {}, force: boolean = false) {
57
+ var before = this._oldLifecycleInfo$ || {}
58
+
59
+ var after = {
60
+ ...before,
61
+ ...this.lifecycle,
62
+ contextPath: this.contextPath,
63
+ ...changes
64
+ }
65
+
66
+ if (!('initialized' in changes) && after.active && !before.initialized) {
67
+ after.initialized = true
68
+ }
69
+
70
+ if (force) {
71
+ after.updated = Date.now()
72
+ }
73
+
74
+ var changed = diff(after, before)
75
+ if (!changed) {
76
+ return
77
+ }
78
+
79
+ this._oldLifecycleInfo$ = after
80
+
81
+ /* page의 이미 초기화된 상태에서 contextPath가 바뀐다면, 무조건 page가 리셋되어야 한다. */
82
+ if (before.initialized && changed.contextPath) {
83
+ await this.pageReset()
84
+ return
85
+ }
86
+
87
+ if (changed.initialized) {
88
+ await this.pageInitialized(after)
89
+ }
90
+
91
+ if ('initialized' in changed) {
92
+ if (changed.initialized) {
93
+ /*
94
+ * 방금 초기화된 경우라면, 엘리먼트들이 만들어지지 않았을 가능성이 있으므로,
95
+ * 다음 animationFrame에서 pageUpdated 콜백을 호출한다.
96
+ */
97
+ requestAnimationFrame(async () => {
98
+ await this.pageUpdated(changed, after, before)
99
+ /* active page인 경우에는, page Context 갱신도 필요할 것이다. */
100
+ after.active && this.updateContext()
101
+ })
102
+ } else {
103
+ await this.pageDisposed(after)
104
+ }
105
+ } else {
106
+ await this.pageUpdated(changed, after, before)
107
+ /* active page인 경우에는, page Context 갱신도 필요할 것이다. */
108
+ after.active && this.updateContext()
109
+ }
110
+ }
111
+
112
+ async pageReset() {
113
+ var { initialized } = this._oldLifecycleInfo$ || {}
114
+
115
+ if (initialized) {
116
+ await this.pageDispose()
117
+ await this.pageUpdate({}, true)
118
+ }
119
+ }
120
+
121
+ async pageDispose() {
122
+ await this.pageUpdate({
123
+ initialized: false
124
+ })
125
+ }
126
+
127
+ pageInitialized(pageInfo: any) {}
128
+ pageUpdated(changes: any, after: any, before: any) {}
129
+ pageDisposed(pageInfo: any) {}
130
+
131
+ /* context */
132
+ updateContext(override?: any) {
133
+ store.dispatch({
134
+ type: UPDATE_CONTEXT,
135
+ context: override ? { ...this.context, ...override } : this.context
136
+ })
137
+ }
138
+
139
+ get context() {
140
+ return {}
141
+ }
142
+ }
@@ -0,0 +1,95 @@
1
+ import '@material/mwc-icon-button'
2
+ import '@material/mwc-button'
3
+
4
+ import { css, html, LitElement } from 'lit'
5
+ import { customElement } from 'lit/decorators'
6
+
7
+ @customElement('home-page')
8
+ export class HomePage extends LitElement {
9
+ static styles = css`
10
+ :host {
11
+ background-color: var(--main-section-background-color);
12
+
13
+ display: block;
14
+ position: relative;
15
+
16
+ --mdc-theme-primary: white;
17
+ }
18
+
19
+ [home] {
20
+ position: absolute;
21
+ left: 20px;
22
+ top: 20px;
23
+ font-size: 2em;
24
+ color: white;
25
+ }
26
+
27
+ [message] {
28
+ background-color: rgba(50, 66, 97, 0.8);
29
+ padding: 60px 50px 0 50px;
30
+ color: #fff;
31
+ text-align: center;
32
+ 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;
44
+ }
45
+
46
+ @media screen and (max-width: 480px) {
47
+ [message] {
48
+ padding: 60px 30px 0 30px;
49
+ color: #fff;
50
+ text-align: center;
51
+ font-size: 15px;
52
+ }
53
+
54
+ [message] strong {
55
+ font-size: 1.6rem;
56
+ }
57
+ }
58
+ `
59
+
60
+ _applicationMeta?: {
61
+ icon: string
62
+ title: string
63
+ description: string
64
+ }
65
+
66
+ render() {
67
+ var { icon, title, description } = this.applicationMeta
68
+
69
+ return html`
70
+ <mwc-icon-button home icon="home" @click=${() => (window.location.href = '/')}></mwc-icon-button>
71
+
72
+ <div message>
73
+ <strong>${title}</strong>
74
+ ${description}
75
+ <img src="/assets/images/home.png" />
76
+ </div>
77
+ `
78
+ }
79
+
80
+ get applicationMeta() {
81
+ if (!this._applicationMeta) {
82
+ var iconLink = document.querySelector('link[rel="application-icon"]') as HTMLLinkElement
83
+ var titleMeta = document.querySelector('meta[name="application-name"]') as HTMLMetaElement
84
+ var descriptionMeta = document.querySelector('meta[name="application-description"]') as HTMLMetaElement
85
+
86
+ this._applicationMeta = {
87
+ icon: iconLink?.href,
88
+ title: titleMeta ? titleMeta.content : 'Things Factory',
89
+ description: descriptionMeta ? descriptionMeta.content : 'Reimagining Software'
90
+ }
91
+ }
92
+
93
+ return this._applicationMeta
94
+ }
95
+ }
package/src/index.ts ADDED
File without changes
File without changes
@@ -0,0 +1,48 @@
1
+ import { getPathInfo } from '@operato/utils'
2
+
3
+ import { SET_DOMAINS, UPDATE_BASE_URL, UPDATE_CONTEXT_PATH, UPDATE_MODULES } from '../actions/app.js'
4
+
5
+ const INITIAL_STATE: {
6
+ baseUrl: string
7
+ contextPath: string
8
+ domains: {
9
+ name: string
10
+ subdomain: string
11
+ }[]
12
+ } = {
13
+ baseUrl: location.origin,
14
+ contextPath: getPathInfo(location.pathname).contextPath,
15
+ domains: []
16
+ }
17
+
18
+ const app = (state = INITIAL_STATE, action: any) => {
19
+ switch (action.type) {
20
+ case UPDATE_MODULES:
21
+ return {
22
+ ...state,
23
+ modules: action.modules
24
+ }
25
+ case UPDATE_BASE_URL:
26
+ return {
27
+ ...state,
28
+ baseUrl: action.baseUrl
29
+ }
30
+ case UPDATE_CONTEXT_PATH:
31
+ return {
32
+ ...state,
33
+ contextPath: action.contextPath
34
+ }
35
+
36
+ case SET_DOMAINS:
37
+ return {
38
+ ...state,
39
+ domains: action.domains,
40
+ domain: action.domain
41
+ }
42
+
43
+ default:
44
+ return state
45
+ }
46
+ }
47
+
48
+ export default app
@@ -0,0 +1,77 @@
1
+ import startCase from 'lodash/startCase'
2
+ import { updateMetadata } from 'pwa-helpers/metadata.js'
3
+
4
+ import {
5
+ REGISTER_NAVIGATION_CALLBACK,
6
+ UNREGISTER_NAVIGATION_CALLBACK,
7
+ UPDATE_ACTIVE_PAGE,
8
+ UPDATE_CONTEXT,
9
+ UPDATE_PAGE
10
+ } from '../actions/route.js'
11
+
12
+ const APP_TITLE_EL = document.querySelector('meta[name="application-name"]') as HTMLMetaElement
13
+
14
+ var appTitle: string | undefined
15
+ if (APP_TITLE_EL) {
16
+ appTitle = APP_TITLE_EL.content
17
+ }
18
+
19
+ const INITIAL_STATE: {
20
+ page: string
21
+ resourceId: string
22
+ params: any
23
+ activePage: any
24
+ context: any
25
+ callbacks: any[]
26
+ } = {
27
+ page: '',
28
+ resourceId: '',
29
+ params: {},
30
+ activePage: null,
31
+ context: {},
32
+ callbacks: []
33
+ }
34
+
35
+ const route = (state = INITIAL_STATE, action: any) => {
36
+ switch (action.type) {
37
+ case UPDATE_PAGE:
38
+ return {
39
+ ...state,
40
+ page: action.page,
41
+ resourceId: action.resourceId,
42
+ params: action.params
43
+ }
44
+ case UPDATE_CONTEXT:
45
+ let title = action.context?.title
46
+ let text = typeof title === 'object' ? title.text : title
47
+
48
+ updateMetadata({
49
+ title: appTitle + (text ? ` - ${startCase(text)}` : '')
50
+ })
51
+ return {
52
+ ...state,
53
+ context: action.context || (state.activePage && state.activePage.context) || {}
54
+ }
55
+ case UPDATE_ACTIVE_PAGE:
56
+ return {
57
+ ...state,
58
+ activePage: action.activePage
59
+ }
60
+
61
+ case REGISTER_NAVIGATION_CALLBACK:
62
+ return {
63
+ ...state,
64
+ callbacks: [...state.callbacks, action.callback]
65
+ }
66
+ case UNREGISTER_NAVIGATION_CALLBACK:
67
+ return {
68
+ ...state,
69
+ callbacks: state.callbacks.filter(callback => callback !== action.callback)
70
+ }
71
+
72
+ default:
73
+ return state
74
+ }
75
+ }
76
+
77
+ export default route
package/src/store.ts ADDED
@@ -0,0 +1,26 @@
1
+ import { lazyReducerEnhancer } from 'pwa-helpers/lazy-reducer-enhancer.js'
2
+ import { applyMiddleware, combineReducers, compose, createStore } from 'redux'
3
+ import thunk from 'redux-thunk'
4
+
5
+ import app from './reducers/app.js'
6
+ import route from './reducers/route.js'
7
+
8
+ declare global {
9
+ var __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: any
10
+ }
11
+
12
+ // Sets up a Chrome extension for time travel debugging.
13
+ // See https://github.com/zalmoxisus/redux-devtools-extension for more information.
14
+ const devCompose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
15
+
16
+ export const store = createStore(
17
+ state => state,
18
+ devCompose(lazyReducerEnhancer(combineReducers), applyMiddleware(thunk))
19
+ )
20
+
21
+ // Initially loaded reducers.
22
+ // @ts-ignore
23
+ store.addReducers({
24
+ app,
25
+ route
26
+ })
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2018",
4
+ "module": "esnext",
5
+ "moduleResolution": "node",
6
+ "noEmitOnError": true,
7
+ "lib": ["es2017", "dom"],
8
+ "strict": true,
9
+ "esModuleInterop": false,
10
+ "allowSyntheticDefaultImports": true,
11
+ "experimentalDecorators": true,
12
+ "useDefineForClassFields": false,
13
+ "importHelpers": true,
14
+ "outDir": "dist",
15
+ "sourceMap": true,
16
+ "inlineSources": true,
17
+ "rootDir": "./",
18
+ "declaration": true,
19
+ "incremental": true,
20
+ "types": ["node", "mocha"]
21
+ },
22
+ "include": ["**/*.ts"]
23
+ }
@@ -0,0 +1,27 @@
1
+ // import { hmrPlugin, presets } from '@open-wc/dev-server-hmr';
2
+
3
+ /** Use Hot Module replacement by adding --hmr to the start command */
4
+ const hmr = process.argv.includes('--hmr');
5
+
6
+ export default /** @type {import('@web/dev-server').DevServerConfig} */ ({
7
+ open: '/demo/',
8
+ /** Use regular watch mode if HMR is not enabled. */
9
+ watch: !hmr,
10
+ /** Resolve bare module imports */
11
+ nodeResolve: {
12
+ exportConditions: ['browser', 'development'],
13
+ },
14
+
15
+ /** Compile JS for older browsers. Requires @web/dev-server-esbuild plugin */
16
+ // esbuildTarget: 'auto'
17
+
18
+ /** Set appIndex to enable SPA routing */
19
+ // appIndex: 'demo/index.html',
20
+
21
+ plugins: [
22
+ /** Use Hot Module Replacement by uncommenting. Requires @open-wc/dev-server-hmr plugin */
23
+ // hmr && hmrPlugin({ exclude: ['**/*/node_modules/**/*'], presets: [presets.litElement] }),
24
+ ],
25
+
26
+ // See documentation for all available options
27
+ });
@@ -0,0 +1,41 @@
1
+ // import { playwrightLauncher } from '@web/test-runner-playwright';
2
+
3
+ const filteredLogs = ['Running in dev mode', 'lit-html is in dev mode'];
4
+
5
+ export default /** @type {import("@web/test-runner").TestRunnerConfig} */ ({
6
+ /** Test files to run */
7
+ files: 'dist/test/**/*.test.js',
8
+
9
+ /** Resolve bare module imports */
10
+ nodeResolve: {
11
+ exportConditions: ['browser', 'development'],
12
+ },
13
+
14
+ /** Filter out lit dev mode logs */
15
+ filterBrowserLogs(log) {
16
+ for (const arg of log.args) {
17
+ if (typeof arg === 'string' && filteredLogs.some(l => arg.includes(l))) {
18
+ return false;
19
+ }
20
+ }
21
+ return true;
22
+ },
23
+
24
+ /** Compile JS for older browsers. Requires @web/dev-server-esbuild plugin */
25
+ // esbuildTarget: 'auto',
26
+
27
+ /** Amount of browsers to run concurrently */
28
+ // concurrentBrowsers: 2,
29
+
30
+ /** Amount of test files per browser to test concurrently */
31
+ // concurrency: 1,
32
+
33
+ /** Browsers to run tests on */
34
+ // browsers: [
35
+ // playwrightLauncher({ product: 'chromium' }),
36
+ // playwrightLauncher({ product: 'firefox' }),
37
+ // playwrightLauncher({ product: 'webkit' }),
38
+ // ],
39
+
40
+ // See documentation for all available options
41
+ });