@tomorrowos/sdk 0.9.40 → 0.9.42
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/LOVABLE_SETUP.md +67 -67
- package/README.md +4 -3
- package/REPLIT_SETUP.md +115 -44
- package/VERCEL_QUESTIONS.md +22 -22
- package/VERCEL_SETUP.md +200 -200
- package/package.json +1 -1
- package/templates/cms-starter/package.json +2 -2
- package/templates/cms-starter/public/methods.js +37 -0
- package/templates/cms-starter/public/panel.css +21 -12
- package/templates/cms-starter-v0/cms-panel/methods.js +37 -0
- package/templates/cms-starter-v0/cms-panel/panel.css +21 -12
- package/templates/cms-starter-v0/package.json +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomorrowos/sdk",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.42",
|
|
4
4
|
"description": "TomorrowOS CMS server SDK - WebSocket transport, pairing, device commands, optional static CMS UI. Includes CLI (tomorrowos init / build) and starter templates.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-cms",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.42",
|
|
4
4
|
"description": "CMS server on @tomorrowos/sdk. Add your UI (React, static files, etc.) alongside this server.",
|
|
5
5
|
"private": true,
|
|
6
6
|
"type": "module",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"build-player": "tomorrowos build --platform tizen"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@tomorrowos/sdk": "^0.9.
|
|
16
|
+
"@tomorrowos/sdk": "^0.9.42",
|
|
17
17
|
"dotenv": "^17.2.3",
|
|
18
18
|
"tsx": "^4.19.0"
|
|
19
19
|
},
|
|
@@ -44,6 +44,41 @@ const UPLOAD_MAX_RETRIES = 3;
|
|
|
44
44
|
const DEVICE_RECONNECT_GRACE_MS = 60000;
|
|
45
45
|
const UPLOAD_TIMEOUT_MS = 120000;
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Apply brand.json to the Control Panel (name + colours). No logo on the panel.
|
|
49
|
+
* Fetches same-origin GET /brand.json served by TomorrowOS.listen().
|
|
50
|
+
*/
|
|
51
|
+
async function applyBrandFromServer() {
|
|
52
|
+
try {
|
|
53
|
+
const res = await fetch("/brand.json", { cache: "no-store" });
|
|
54
|
+
if (!res.ok) return;
|
|
55
|
+
const brand = await res.json();
|
|
56
|
+
if (!brand || typeof brand !== "object") return;
|
|
57
|
+
|
|
58
|
+
const name = String(brand.name || "").trim() || "TomorrowOS";
|
|
59
|
+
const panelTitle = `${name} Control Panel`;
|
|
60
|
+
document.title = panelTitle;
|
|
61
|
+
const heading = document.querySelector(".app-header h1");
|
|
62
|
+
if (heading) heading.textContent = panelTitle;
|
|
63
|
+
|
|
64
|
+
const tagline = String(brand.tagline || "").trim();
|
|
65
|
+
const subtitle = document.querySelector(".app-header p");
|
|
66
|
+
if (subtitle && tagline) subtitle.textContent = tagline;
|
|
67
|
+
|
|
68
|
+
const root = document.documentElement;
|
|
69
|
+
const primary = String(brand.primaryColor || "").trim();
|
|
70
|
+
const background = String(brand.backgroundColor || "").trim();
|
|
71
|
+
const text = String(brand.textColor || "").trim();
|
|
72
|
+
const secondary = String(brand.secondaryColor || "").trim();
|
|
73
|
+
if (primary) root.style.setProperty("--brand-primary", primary);
|
|
74
|
+
if (background) root.style.setProperty("--brand-background", background);
|
|
75
|
+
if (text) root.style.setProperty("--brand-text", text);
|
|
76
|
+
if (secondary) root.style.setProperty("--brand-secondary", secondary);
|
|
77
|
+
} catch (_) {
|
|
78
|
+
/* keep starter defaults */
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
47
82
|
function escapeHtml(value) {
|
|
48
83
|
return String(value ?? "")
|
|
49
84
|
.replace(/&/g, "&")
|
|
@@ -2285,6 +2320,8 @@ function startServerStatusPolling() {
|
|
|
2285
2320
|
}
|
|
2286
2321
|
|
|
2287
2322
|
document.addEventListener("DOMContentLoaded", () => {
|
|
2323
|
+
void applyBrandFromServer();
|
|
2324
|
+
|
|
2288
2325
|
const cmsUrlSection = document.getElementById("cmsUrlSection");
|
|
2289
2326
|
if (cmsUrlSection && !isLocalPanelHost(window.location.hostname)) {
|
|
2290
2327
|
cmsUrlSection.classList.add("hidden");
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--brand-primary: #ff8a3d;
|
|
3
|
+
--brand-background: #f4f3f0;
|
|
4
|
+
--brand-text: #0a0908;
|
|
5
|
+
--brand-secondary: #fafaf9;
|
|
6
|
+
--brand-header-bg: #0a0908;
|
|
7
|
+
--brand-header-fg: #fafaf9;
|
|
8
|
+
}
|
|
9
|
+
|
|
1
10
|
* {
|
|
2
11
|
box-sizing: border-box;
|
|
3
12
|
}
|
|
@@ -5,14 +14,14 @@
|
|
|
5
14
|
body {
|
|
6
15
|
margin: 0;
|
|
7
16
|
font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
|
|
8
|
-
background:
|
|
9
|
-
color:
|
|
17
|
+
background: var(--brand-background);
|
|
18
|
+
color: var(--brand-text);
|
|
10
19
|
}
|
|
11
20
|
|
|
12
21
|
.app-header {
|
|
13
22
|
padding: 1rem 1.5rem;
|
|
14
|
-
background:
|
|
15
|
-
color:
|
|
23
|
+
background: var(--brand-header-bg);
|
|
24
|
+
color: var(--brand-header-fg);
|
|
16
25
|
}
|
|
17
26
|
|
|
18
27
|
.app-header h1 {
|
|
@@ -79,7 +88,7 @@ body {
|
|
|
79
88
|
}
|
|
80
89
|
|
|
81
90
|
.playlist-catalog-item--active {
|
|
82
|
-
border-color:
|
|
91
|
+
border-color: var(--brand-primary);
|
|
83
92
|
background: #fff5ee;
|
|
84
93
|
}
|
|
85
94
|
|
|
@@ -579,14 +588,14 @@ button:hover {
|
|
|
579
588
|
}
|
|
580
589
|
|
|
581
590
|
button.primary {
|
|
582
|
-
background:
|
|
583
|
-
border-color: #
|
|
584
|
-
color:
|
|
591
|
+
background: var(--brand-primary);
|
|
592
|
+
border-color: color-mix(in srgb, var(--brand-primary) 82%, #000);
|
|
593
|
+
color: var(--brand-text);
|
|
585
594
|
font-weight: 600;
|
|
586
595
|
}
|
|
587
596
|
|
|
588
597
|
button.primary:hover {
|
|
589
|
-
background: #
|
|
598
|
+
background: color-mix(in srgb, var(--brand-primary) 88%, #fff);
|
|
590
599
|
}
|
|
591
600
|
|
|
592
601
|
button.danger {
|
|
@@ -670,7 +679,7 @@ button.danger {
|
|
|
670
679
|
.upload-progress-bar {
|
|
671
680
|
width: 0%;
|
|
672
681
|
height: 100%;
|
|
673
|
-
background:
|
|
682
|
+
background: var(--brand-primary);
|
|
674
683
|
transition: width 120ms linear;
|
|
675
684
|
}
|
|
676
685
|
|
|
@@ -710,7 +719,7 @@ button.danger {
|
|
|
710
719
|
}
|
|
711
720
|
|
|
712
721
|
.playlist-item--drop-target {
|
|
713
|
-
border-color:
|
|
722
|
+
border-color: var(--brand-primary);
|
|
714
723
|
box-shadow: 0 0 0 2px rgba(255, 138, 61, 0.25);
|
|
715
724
|
}
|
|
716
725
|
|
|
@@ -1078,7 +1087,7 @@ button.danger {
|
|
|
1078
1087
|
}
|
|
1079
1088
|
|
|
1080
1089
|
.player-platform-link:focus-visible {
|
|
1081
|
-
outline: 2px solid
|
|
1090
|
+
outline: 2px solid var(--brand-primary);
|
|
1082
1091
|
outline-offset: 3px;
|
|
1083
1092
|
}
|
|
1084
1093
|
|
|
@@ -44,6 +44,41 @@ const UPLOAD_MAX_RETRIES = 3;
|
|
|
44
44
|
const DEVICE_RECONNECT_GRACE_MS = 60000;
|
|
45
45
|
const UPLOAD_TIMEOUT_MS = 120000;
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Apply brand.json to the Control Panel (name + colours). No logo on the panel.
|
|
49
|
+
* Fetches same-origin GET /brand.json served by TomorrowOS.listen().
|
|
50
|
+
*/
|
|
51
|
+
async function applyBrandFromServer() {
|
|
52
|
+
try {
|
|
53
|
+
const res = await fetch("/brand.json", { cache: "no-store" });
|
|
54
|
+
if (!res.ok) return;
|
|
55
|
+
const brand = await res.json();
|
|
56
|
+
if (!brand || typeof brand !== "object") return;
|
|
57
|
+
|
|
58
|
+
const name = String(brand.name || "").trim() || "TomorrowOS";
|
|
59
|
+
const panelTitle = `${name} Control Panel`;
|
|
60
|
+
document.title = panelTitle;
|
|
61
|
+
const heading = document.querySelector(".app-header h1");
|
|
62
|
+
if (heading) heading.textContent = panelTitle;
|
|
63
|
+
|
|
64
|
+
const tagline = String(brand.tagline || "").trim();
|
|
65
|
+
const subtitle = document.querySelector(".app-header p");
|
|
66
|
+
if (subtitle && tagline) subtitle.textContent = tagline;
|
|
67
|
+
|
|
68
|
+
const root = document.documentElement;
|
|
69
|
+
const primary = String(brand.primaryColor || "").trim();
|
|
70
|
+
const background = String(brand.backgroundColor || "").trim();
|
|
71
|
+
const text = String(brand.textColor || "").trim();
|
|
72
|
+
const secondary = String(brand.secondaryColor || "").trim();
|
|
73
|
+
if (primary) root.style.setProperty("--brand-primary", primary);
|
|
74
|
+
if (background) root.style.setProperty("--brand-background", background);
|
|
75
|
+
if (text) root.style.setProperty("--brand-text", text);
|
|
76
|
+
if (secondary) root.style.setProperty("--brand-secondary", secondary);
|
|
77
|
+
} catch (_) {
|
|
78
|
+
/* keep starter defaults */
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
47
82
|
function escapeHtml(value) {
|
|
48
83
|
return String(value ?? "")
|
|
49
84
|
.replace(/&/g, "&")
|
|
@@ -2285,6 +2320,8 @@ function startServerStatusPolling() {
|
|
|
2285
2320
|
}
|
|
2286
2321
|
|
|
2287
2322
|
document.addEventListener("DOMContentLoaded", () => {
|
|
2323
|
+
void applyBrandFromServer();
|
|
2324
|
+
|
|
2288
2325
|
const cmsUrlSection = document.getElementById("cmsUrlSection");
|
|
2289
2326
|
if (cmsUrlSection && !isLocalPanelHost(window.location.hostname)) {
|
|
2290
2327
|
cmsUrlSection.classList.add("hidden");
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--brand-primary: #ff8a3d;
|
|
3
|
+
--brand-background: #f4f3f0;
|
|
4
|
+
--brand-text: #0a0908;
|
|
5
|
+
--brand-secondary: #fafaf9;
|
|
6
|
+
--brand-header-bg: #0a0908;
|
|
7
|
+
--brand-header-fg: #fafaf9;
|
|
8
|
+
}
|
|
9
|
+
|
|
1
10
|
* {
|
|
2
11
|
box-sizing: border-box;
|
|
3
12
|
}
|
|
@@ -5,14 +14,14 @@
|
|
|
5
14
|
body {
|
|
6
15
|
margin: 0;
|
|
7
16
|
font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
|
|
8
|
-
background:
|
|
9
|
-
color:
|
|
17
|
+
background: var(--brand-background);
|
|
18
|
+
color: var(--brand-text);
|
|
10
19
|
}
|
|
11
20
|
|
|
12
21
|
.app-header {
|
|
13
22
|
padding: 1rem 1.5rem;
|
|
14
|
-
background:
|
|
15
|
-
color:
|
|
23
|
+
background: var(--brand-header-bg);
|
|
24
|
+
color: var(--brand-header-fg);
|
|
16
25
|
}
|
|
17
26
|
|
|
18
27
|
.app-header h1 {
|
|
@@ -79,7 +88,7 @@ body {
|
|
|
79
88
|
}
|
|
80
89
|
|
|
81
90
|
.playlist-catalog-item--active {
|
|
82
|
-
border-color:
|
|
91
|
+
border-color: var(--brand-primary);
|
|
83
92
|
background: #fff5ee;
|
|
84
93
|
}
|
|
85
94
|
|
|
@@ -579,14 +588,14 @@ button:hover {
|
|
|
579
588
|
}
|
|
580
589
|
|
|
581
590
|
button.primary {
|
|
582
|
-
background:
|
|
583
|
-
border-color: #
|
|
584
|
-
color:
|
|
591
|
+
background: var(--brand-primary);
|
|
592
|
+
border-color: color-mix(in srgb, var(--brand-primary) 82%, #000);
|
|
593
|
+
color: var(--brand-text);
|
|
585
594
|
font-weight: 600;
|
|
586
595
|
}
|
|
587
596
|
|
|
588
597
|
button.primary:hover {
|
|
589
|
-
background: #
|
|
598
|
+
background: color-mix(in srgb, var(--brand-primary) 88%, #fff);
|
|
590
599
|
}
|
|
591
600
|
|
|
592
601
|
button.danger {
|
|
@@ -670,7 +679,7 @@ button.danger {
|
|
|
670
679
|
.upload-progress-bar {
|
|
671
680
|
width: 0%;
|
|
672
681
|
height: 100%;
|
|
673
|
-
background:
|
|
682
|
+
background: var(--brand-primary);
|
|
674
683
|
transition: width 120ms linear;
|
|
675
684
|
}
|
|
676
685
|
|
|
@@ -710,7 +719,7 @@ button.danger {
|
|
|
710
719
|
}
|
|
711
720
|
|
|
712
721
|
.playlist-item--drop-target {
|
|
713
|
-
border-color:
|
|
722
|
+
border-color: var(--brand-primary);
|
|
714
723
|
box-shadow: 0 0 0 2px rgba(255, 138, 61, 0.25);
|
|
715
724
|
}
|
|
716
725
|
|
|
@@ -1078,7 +1087,7 @@ button.danger {
|
|
|
1078
1087
|
}
|
|
1079
1088
|
|
|
1080
1089
|
.player-platform-link:focus-visible {
|
|
1081
|
-
outline: 2px solid
|
|
1090
|
+
outline: 2px solid var(--brand-primary);
|
|
1082
1091
|
outline-offset: 3px;
|
|
1083
1092
|
}
|
|
1084
1093
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-cms",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.42",
|
|
4
4
|
"description": "TomorrowOS CMS for Vercel / v0 Publish (Fluid Function + WebSockets + optional Next Preview).",
|
|
5
5
|
"private": true,
|
|
6
6
|
"type": "module",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"build-player": "tomorrowos build --platform tizen"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@tomorrowos/sdk": "^0.9.
|
|
20
|
+
"@tomorrowos/sdk": "^0.9.42",
|
|
21
21
|
"dotenv": "^17.2.3",
|
|
22
22
|
"tsx": "^4.19.0"
|
|
23
23
|
},
|