create-switch-framework-app 0.1.0 → 0.2.2

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 (37) hide show
  1. package/README.md +25 -25
  2. package/bin/create-switch-framework-app.js +48 -35
  3. package/package.json +1 -1
  4. package/templates/electron/base/app/(tabs)/+not-found.js +157 -157
  5. package/templates/electron/base/app/(tabs)/_layout.js +57 -93
  6. package/templates/electron/base/app/(tabs)/explore.js +55 -44
  7. package/templates/electron/base/app/(tabs)/index.js +10 -24
  8. package/templates/electron/base/app/+not-found.js +148 -158
  9. package/templates/electron/base/app/_layout.js +24 -44
  10. package/templates/electron/base/app/index.js +16 -30
  11. package/templates/electron/base/assets/logo.svg +5 -5
  12. package/templates/electron/base/components/SwSplashScreen.js +1 -1
  13. package/templates/electron/base/components/SwStarterSplashScreen.js +130 -140
  14. package/templates/electron/base/components/SwTabBar.js +146 -153
  15. package/templates/electron/base/electron/electron-builder.json +19 -19
  16. package/templates/electron/base/electron/main.js +30 -30
  17. package/templates/electron/base/electron/preload.js +5 -5
  18. package/templates/electron/base/index.js +2 -3
  19. package/templates/electron/base/main.js +1 -1
  20. package/templates/electron/base/preload.js +1 -1
  21. package/templates/electron/base/server.js +27 -42
  22. package/templates/web/base/app/(tabs)/+not-found.js +157 -157
  23. package/templates/web/base/app/(tabs)/_layout.js +57 -93
  24. package/templates/web/base/app/(tabs)/explore.js +55 -44
  25. package/templates/web/base/app/(tabs)/index.js +10 -24
  26. package/templates/web/base/app/+not-found.js +148 -158
  27. package/templates/web/base/app/_layout.js +24 -44
  28. package/templates/web/base/app/index.js +16 -30
  29. package/templates/web/base/assets/logo.svg +5 -5
  30. package/templates/web/base/components/SwSplashScreen.js +1 -1
  31. package/templates/web/base/components/SwStarterSplashScreen.js +130 -140
  32. package/templates/web/base/components/SwTabBar.js +146 -153
  33. package/templates/web/base/index.js +2 -3
  34. package/templates/electron/base/app/(tabs)/register.js +0 -12
  35. package/templates/electron/base/app/register.js +0 -12
  36. package/templates/web/base/app/(tabs)/register.js +0 -12
  37. package/templates/web/base/app/register.js +0 -12
@@ -1,140 +1,130 @@
1
- export class SwStarterSplashScreen extends HTMLElement {
2
- constructor() {
3
- super();
4
- this.attachShadow({ mode: 'open' });
5
- }
6
-
7
- connectedCallback() {
8
- this.render();
9
- }
10
-
11
- render() {
12
- this.shadowRoot.innerHTML = `
13
- ${this.styleSheet()}
14
- <div class="wrap">
15
- <div class="card">
16
- <div class="logo-container">
17
- <img class="logo" src="/assets/logo.svg" alt="Expo" />
18
- </div>
19
- <div class="title">Switch Framework</div>
20
- <div class="sub">Launching...</div>
21
-
22
- <div class="loader-container">
23
- <div class="loader"></div>
24
- </div>
25
- </div>
26
- </div>
27
- `;
28
- }
29
-
30
- styleSheet() {
31
- return `
32
- <style>
33
- :host {
34
- position: fixed;
35
- inset: 0;
36
- display: block;
37
- background: var(--page_background, #fff);
38
- z-index: 9999;
39
- }
40
-
41
- * {
42
- box-sizing: border-box;
43
- font-family: var(--font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
44
- }
45
-
46
- .wrap {
47
- height: 100%;
48
- display: flex;
49
- align-items: center;
50
- justify-content: center;
51
- padding: 18px;
52
- }
53
-
54
- .card {
55
- width: min(520px, 100%);
56
- display: flex;
57
- flex-direction: column;
58
- align-items: center;
59
- gap: 16px;
60
- }
61
-
62
- .logo-container {
63
- display: flex;
64
- align-items: center;
65
- justify-content: center;
66
- width: 100px;
67
- height: 100px;
68
- background: linear-gradient(135deg, #0091ff 0%, #0073e6 100%);
69
- border-radius: 28px;
70
- box-shadow: 0 20px 40px rgba(0, 145, 255, 0.25);
71
- animation: fadeInScale 0.6s ease-out;
72
- }
73
-
74
- .logo {
75
- width: 56px;
76
- height: 56px;
77
- filter: brightness(0) invert(1);
78
- }
79
-
80
- .title {
81
- font-weight: 700;
82
- font-size: 24px;
83
- color: var(--main_text, #000);
84
- animation: fadeIn 0.8s ease-out 0.2s both;
85
- }
86
-
87
- .sub {
88
- font-weight: 600;
89
- font-size: 13px;
90
- color: var(--sub_text, #666);
91
- animation: fadeIn 0.8s ease-out 0.3s both;
92
- }
93
-
94
- .loader-container {
95
- margin-top: 12px;
96
- animation: fadeIn 0.8s ease-out 0.4s both;
97
- }
98
-
99
- .loader {
100
- width: 48px;
101
- height: 48px;
102
- border: 3px solid rgba(0, 145, 255, 0.15);
103
- border-top: 3px solid #0091ff;
104
- border-radius: 50%;
105
- animation: spin 1s linear infinite;
106
- }
107
-
108
- @keyframes spin {
109
- to {
110
- transform: rotate(360deg);
111
- }
112
- }
113
-
114
- @keyframes fadeIn {
115
- from {
116
- opacity: 0;
117
- }
118
- to {
119
- opacity: 1;
120
- }
121
- }
122
-
123
- @keyframes fadeInScale {
124
- from {
125
- opacity: 0;
126
- transform: scale(0.8);
127
- }
128
- to {
129
- opacity: 1;
130
- transform: scale(1);
131
- }
132
- }
133
- </style>
134
- `;
135
- }
136
- }
137
-
138
- if (!customElements.get('sw-starter-splash')) {
139
- customElements.define('sw-starter-splash', SwStarterSplashScreen);
140
- }
1
+ import { SwitchComponent } from 'switch-framework';
2
+
3
+ export class SwStarterSplashScreen extends SwitchComponent {
4
+ static tag = 'sw-starter-splash';
5
+
6
+ render() {
7
+ return `
8
+ <div class="wrap">
9
+ <div class="card">
10
+ <div class="logo-container">
11
+ <img class="logo" src="/assets/logo.svg" alt="Switch Framework" />
12
+ </div>
13
+ <div class="title">Switch Framework</div>
14
+ <div class="sub">Launching...</div>
15
+
16
+ <div class="loader-container">
17
+ <div class="loader"></div>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ `;
22
+ }
23
+
24
+ styleSheet() {
25
+ return `
26
+ <style>
27
+ :host {
28
+ position: fixed;
29
+ inset: 0;
30
+ display: block;
31
+ background: var(--page_background, #fff);
32
+ z-index: 9999;
33
+ }
34
+
35
+ * {
36
+ box-sizing: border-box;
37
+ font-family: var(--font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
38
+ }
39
+
40
+ .wrap {
41
+ height: 100%;
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ padding: 18px;
46
+ }
47
+
48
+ .card {
49
+ width: min(520px, 100%);
50
+ display: flex;
51
+ flex-direction: column;
52
+ align-items: center;
53
+ gap: 16px;
54
+ }
55
+
56
+ .logo-container {
57
+ display: flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ width: 100px;
61
+ height: 100px;
62
+ background: linear-gradient(135deg, #0091ff 0%, #0073e6 100%);
63
+ border-radius: 28px;
64
+ box-shadow: 0 20px 40px rgba(0, 145, 255, 0.25);
65
+ animation: fadeInScale 0.6s ease-out;
66
+ }
67
+
68
+ .logo {
69
+ width: 56px;
70
+ height: 56px;
71
+ filter: brightness(0) invert(1);
72
+ }
73
+
74
+ .title {
75
+ font-weight: 700;
76
+ font-size: 24px;
77
+ color: var(--main_text, #000);
78
+ animation: fadeIn 0.8s ease-out 0.2s both;
79
+ }
80
+
81
+ .sub {
82
+ font-weight: 600;
83
+ font-size: 13px;
84
+ color: var(--sub_text, #666);
85
+ animation: fadeIn 0.8s ease-out 0.3s both;
86
+ }
87
+
88
+ .loader-container {
89
+ margin-top: 12px;
90
+ animation: fadeIn 0.8s ease-out 0.4s both;
91
+ }
92
+
93
+ .loader {
94
+ width: 48px;
95
+ height: 48px;
96
+ border: 3px solid rgba(0, 145, 255, 0.15);
97
+ border-top: 3px solid #0091ff;
98
+ border-radius: 50%;
99
+ animation: spin 1s linear infinite;
100
+ }
101
+
102
+ @keyframes spin {
103
+ to {
104
+ transform: rotate(360deg);
105
+ }
106
+ }
107
+
108
+ @keyframes fadeIn {
109
+ from {
110
+ opacity: 0;
111
+ }
112
+ to {
113
+ opacity: 1;
114
+ }
115
+ }
116
+
117
+ @keyframes fadeInScale {
118
+ from {
119
+ opacity: 0;
120
+ transform: scale(0.8);
121
+ }
122
+ to {
123
+ opacity: 1;
124
+ transform: scale(1);
125
+ }
126
+ }
127
+ </style>
128
+ `;
129
+ }
130
+ }
@@ -1,153 +1,146 @@
1
- export class SwTabBar extends HTMLElement {
2
- constructor() {
3
- super();
4
- this.attachShadow({ mode: 'open' });
5
- this._unsub = null;
6
- }
7
-
8
- connectedCallback() {
9
- this.render();
10
- this.updateActive();
11
-
12
- if (globalStates?.subscribe) {
13
- this._unsub = globalStates.subscribe(() => this.updateActive());
14
- }
15
-
16
- this.shadowRoot.addEventListener('click', (e) => {
17
- const btn = e.target?.closest?.('button[data-route]');
18
- if (!btn) return;
19
- const route = btn.getAttribute('data-route');
20
- const navigate = globalStates?.getState ? globalStates.getState('navigate') : null;
21
- if (typeof navigate === 'function') navigate(route);
22
- });
23
- }
24
-
25
- disconnectedCallback() {
26
- if (this._unsub) this._unsub();
27
- }
28
-
29
- getTabs() {
30
- const layout = globalStates?.getState ? globalStates.getState('tabsLayout') : null;
31
- const tabs = Array.isArray(layout?.tabs) ? layout.tabs : [];
32
- return tabs;
33
- }
34
-
35
- updateActive() {
36
- const activeRoute = globalStates?.getState ? globalStates.getState('activeRoute') : '';
37
- const tabs = this.getTabs();
38
-
39
- tabs.forEach((t) => {
40
- const el = this.shadowRoot.getElementById(`tab-${t.name}`);
41
- if (!el) return;
42
- const isActive = String(activeRoute || '').startsWith(String(t.name));
43
- el.classList.toggle('active', isActive);
44
- });
45
- }
46
-
47
- render() {
48
- const tabs = this.getTabs();
49
-
50
- this.shadowRoot.innerHTML = `
51
- ${this.styleSheet()}
52
- <nav class="bar" aria-label="Bottom tabs">
53
- ${tabs.map((t) => `
54
- <button class="tab" id="tab-${t.name}" data-route="${t.name}" type="button">
55
- <span class="icon">${this.getIcon(t.icon)}</span>
56
- <span class="label">${t.title || t.name}</span>
57
- </button>
58
- `).join('')}
59
- </nav>
60
- `;
61
- }
62
-
63
- getIcon(name) {
64
- const map = {
65
- home: `<span class='switch_icon_house'></span>`,
66
- compass: `<span class='switch_icon_compass'></span>`,
67
- settings: `<span class='switch_icon_gear'></span>`
68
- };
69
- return map[name] || map.home;
70
- }
71
-
72
- styleSheet() {
73
- return `
74
- <style>
75
- @import '/assets/icons/style.css';
76
-
77
- :host {
78
- display: block;
79
- width: 100%;
80
- background: transparent;
81
- }
82
-
83
- * {
84
- box-sizing: border-box;
85
- font-family: var(--font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
86
- }
87
-
88
- .bar {
89
- display: grid;
90
- grid-template-columns: repeat(2, 1fr);
91
- gap: 12px;
92
- padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
93
- border-top: 1px solid var(--border_color, #e5e5e5);
94
- background: rgba(255, 255, 255, 0.95);
95
- backdrop-filter: saturate(180%) blur(10px);
96
- }
97
-
98
- :root[data-theme="dark"] .bar {
99
- background: rgba(11, 15, 20, 0.95);
100
- border-top-color: rgba(255, 255, 255, 0.1);
101
- }
102
-
103
- .tab {
104
- appearance: none;
105
- border: none;
106
- background: transparent;
107
- border-radius: 20px;
108
- padding: 12px 14px;
109
- cursor: pointer;
110
- display: flex;
111
- flex-direction: column;
112
- align-items: center;
113
- gap: 8px;
114
- color: var(--sub_text, #666);
115
- font-weight: 600;
116
- transition: all 0.2s ease;
117
- }
118
-
119
- .tab:active {
120
- transform: scale(0.95);
121
- }
122
-
123
- .tab.active {
124
- background: rgba(0, 0, 0, 0.06);
125
- color: var(--main_text, #000);
126
- }
127
-
128
- :root[data-theme="dark"] .tab.active {
129
- background: rgba(255, 255, 255, 0.1);
130
- }
131
-
132
- .icon {
133
- display: flex;
134
- align-items: center;
135
- justify-content: center;
136
- font-size: 24px;
137
- line-height: 1;
138
- }
139
-
140
- .label {
141
- display: block;
142
- text-align: center;
143
- font-size: 11px;
144
- font-weight: 600;
145
- }
146
- </style>
147
- `;
148
- }
149
- }
150
-
151
- if (!customElements.get('sw-tab-bar')) {
152
- customElements.define('sw-tab-bar', SwTabBar);
153
- }
1
+ import { SwitchComponent } from 'switch-framework';
2
+ import { navigate, useRouteChangesSubscriber, getActiveRoute } from 'switch-framework/router';
3
+
4
+ export class SwTabBar extends SwitchComponent {
5
+ static tag = 'sw-tab-bar';
6
+
7
+ connected() {
8
+ this.updateActive();
9
+ this._unsub = useRouteChangesSubscriber(() => this.updateActive());
10
+
11
+ this.shadowRoot.addEventListener('click', (e) => {
12
+ const btn = e.target?.closest?.('button[data-route]');
13
+ if (!btn) return;
14
+ const route = btn.getAttribute('data-route');
15
+ navigate(route);
16
+ });
17
+ }
18
+
19
+ disconnected() {
20
+ if (this._unsub) this._unsub();
21
+ }
22
+
23
+ getTabs() {
24
+ const layout = globalStates?.getState ? globalStates.getState('tabsLayout') : null;
25
+ const tabs = Array.isArray(layout?.tabs) ? layout.tabs : [];
26
+ return tabs;
27
+ }
28
+
29
+ updateActive() {
30
+ const activeRoute = getActiveRoute();
31
+ const tabs = this.getTabs();
32
+
33
+ tabs.forEach((t) => {
34
+ const el = this.shadowRoot?.getElementById?.(`tab-${t.name}`);
35
+ if (!el) return;
36
+ const matchList = Array.isArray(t?.match) ? t.match : [t.name].filter(Boolean);
37
+ const isActive = matchList.some((m) => String(activeRoute || '').startsWith(String(m)) || String(activeRoute || '') === String(m));
38
+ el.classList.toggle('active', isActive);
39
+ });
40
+ }
41
+
42
+ getIcon(name) {
43
+ const map = {
44
+ home: `<span class='switch_icon_house'></span>`,
45
+ compass: `<span class='switch_icon_compass'></span>`,
46
+ settings: `<span class='switch_icon_gear'></span>`
47
+ };
48
+ return map[name] || map.home;
49
+ }
50
+
51
+ render() {
52
+ const tabs = this.getTabs();
53
+
54
+ return `
55
+ <nav class="bar" aria-label="Bottom tabs">
56
+ ${tabs.map((t) => {
57
+ const route = t.initialRoute || (t.path ? t.path.replace(/^\//, '') : t.name);
58
+ return `
59
+ <button class="tab" id="tab-${t.name}" data-route="${route || t.name}" type="button">
60
+ <span class="icon">${this.getIcon(t.icon)}</span>
61
+ <span class="label">${t.title || t.name}</span>
62
+ </button>
63
+ `;
64
+ }).join('')}
65
+ </nav>
66
+ `;
67
+ }
68
+
69
+ styleSheet() {
70
+ return `
71
+ <style>
72
+ @import '/assets/icons/style.css';
73
+
74
+ :host {
75
+ display: block;
76
+ width: 100%;
77
+ background: transparent;
78
+ }
79
+
80
+ * {
81
+ box-sizing: border-box;
82
+ font-family: var(--font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
83
+ }
84
+
85
+ .bar {
86
+ display: grid;
87
+ grid-template-columns: repeat(2, 1fr);
88
+ gap: 12px;
89
+ padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
90
+ border-top: 1px solid var(--border_color, #e5e5e5);
91
+ background: rgba(255, 255, 255, 0.95);
92
+ backdrop-filter: saturate(180%) blur(10px);
93
+ }
94
+
95
+ :root[data-theme="dark"] .bar {
96
+ background: rgba(11, 15, 20, 0.95);
97
+ border-top-color: rgba(255, 255, 255, 0.1);
98
+ }
99
+
100
+ .tab {
101
+ appearance: none;
102
+ border: none;
103
+ background: transparent;
104
+ border-radius: 20px;
105
+ padding: 12px 14px;
106
+ cursor: pointer;
107
+ display: flex;
108
+ flex-direction: column;
109
+ align-items: center;
110
+ gap: 8px;
111
+ color: var(--sub_text, #666);
112
+ font-weight: 600;
113
+ transition: all 0.2s ease;
114
+ }
115
+
116
+ .tab:active {
117
+ transform: scale(0.95);
118
+ }
119
+
120
+ .tab.active {
121
+ background: rgba(0, 0, 0, 0.06);
122
+ color: var(--main_text, #000);
123
+ }
124
+
125
+ :root[data-theme="dark"] .tab.active {
126
+ background: rgba(255, 255, 255, 0.1);
127
+ }
128
+
129
+ .icon {
130
+ display: flex;
131
+ align-items: center;
132
+ justify-content: center;
133
+ font-size: 24px;
134
+ line-height: 1;
135
+ }
136
+
137
+ .label {
138
+ display: block;
139
+ text-align: center;
140
+ font-size: 11px;
141
+ font-weight: 600;
142
+ }
143
+ </style>
144
+ `;
145
+ }
146
+ }
@@ -1,5 +1,4 @@
1
- import { startApp } from '/switch-framework/index.js';
1
+ import { startApp } from 'switch-framework';
2
2
  import layout from './app/_layout.js';
3
- import { appRegisters } from './app/register.js';
4
3
 
5
- startApp(layout, appRegisters);
4
+ startApp(layout);
@@ -1,12 +0,0 @@
1
- export async function appRegisters() {
2
- await Promise.all([
3
- import('../components/SwStarterSplashScreen.js'),
4
- import('../components/SwTabBar.js'),
5
-
6
- import('./index.js'),
7
- import('./+not-found.js'),
8
- import('./(tabs)/_layout.js'),
9
- import('./(tabs)/index.js'),
10
- import('./(tabs)/explore.js')
11
- ]);
12
- }
@@ -1,12 +0,0 @@
1
- export async function appRegisters() {
2
- await Promise.all([
3
- import('../components/SwStarterSplashScreen.js'),
4
- import('../components/SwTabBar.js'),
5
-
6
- import('./index.js'),
7
- import('./+not-found.js'),
8
- import('./(tabs)/_layout.js'),
9
- import('./(tabs)/index.js'),
10
- import('./(tabs)/explore.js')
11
- ]);
12
- }
@@ -1,12 +0,0 @@
1
- export async function appRegisters() {
2
- await Promise.all([
3
- import('../components/SwStarterSplashScreen.js'),
4
- import('../components/SwTabBar.js'),
5
-
6
- import('./index.js'),
7
- import('./+not-found.js'),
8
- import('./(tabs)/_layout.js'),
9
- import('./(tabs)/index.js'),
10
- import('./(tabs)/explore.js')
11
- ]);
12
- }
@@ -1,12 +0,0 @@
1
- export async function appRegisters() {
2
- await Promise.all([
3
- import('../components/SwStarterSplashScreen.js'),
4
- import('../components/SwTabBar.js'),
5
-
6
- import('./index.js'),
7
- import('./+not-found.js'),
8
- import('./(tabs)/_layout.js'),
9
- import('./(tabs)/index.js'),
10
- import('./(tabs)/explore.js')
11
- ]);
12
- }