openvibers/openvibe.network Commits
openvibe-shared v1.29.1 (from its earlier pin): changing the theme repaints the page background, bright accents get dark button text (WCAG), the navbar brand is more compact. Account page: primary buttons use the theme's on-accent colour, the theme switcher applies through the shared loader (canvas and browser UI follow), and every text field follows the theme (input colour, hover tint, accent focus ring, placeholder, invalid state); the theme submission form uses the page's field style with a hint. npm test: deploy wrapper: all checks passed
Changes
@@@ -22,7 +22,7 @@"multer": "^1.4.5-lts.1","openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.76.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.12.0",-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.28.1",++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.29.1","uuid": "^11.1.0","web-push": "^3.6.7"}@@@ -1490,9 +1490,9 @@}},"node_modules/openvibe-shared": {-- "version": "1.28.1",-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.28.1",-- "integrity": "sha512-AV39sRi9hm8QETRLM1c6q7nrU8XWPUZzCxZP+h7Cho+LsJ47szHtMk3YdCQHT8+aSC5Hpu68EU8sCvbagR+a0g==",++ "version": "1.29.1",++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.29.1",++ "integrity": "sha512-HI1aySq1Lipd/GRGI0exL98LVQ2UXWeIlYk3TaTgMsjV/S1L5tTyaI+tNKJ8q8zKpMNdXj0hSflENBE97i/CxQ==","license": "MIT","dependencies": {"jsonwebtoken": "^9.0.0"@@@ -25,7 +25,7 @@"multer": "^1.4.5-lts.1","openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.76.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.12.0",-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.28.1",++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.29.1","uuid": "^11.1.0","web-push": "^3.6.7"}@@@ -84,7 +84,7 @@ body{min-height:100%;color:var(--text);font-family:'Inter',-apple-system,BlinkMa/* Buttons */.btn{padding:8px 16px;border:none;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer;transition:all .15s;display:inline-flex;align-items:center;gap:6px}--.btn-primary{background:var(--accent);color:#fff}++.btn-primary{background:var(--accent);color:var(--on-accent,#fff)}.btn-primary:hover{background:var(--accent-dark)}.btn-outline{background:transparent;border:1px solid var(--border);color:var(--text)}.btn-outline:hover{border-color:var(--accent-dark);color:var(--accent-light)}@@@ -82,18 +82,31 @@ body{min-height:100%;color:var(--text);font-family:'Inter',-apple-system,BlinkMa/* Form fields */.form-field{margin-bottom:14px}.form-field label{display:block;font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:5px}--.form-field input,.form-field select,.form-field textarea{-- width:100%;padding:10px 12px;background:var(--bg-input);border:1px solid var(--border);-- border-radius:8px;color:var(--text);font-size:13px;outline:none;transition:border-color .2s;--}--.form-field input:focus,.form-field select:focus,.form-field textarea:focus{border-color:var(--accent)}++/* Every text field on the page follows the active theme: its input colour, a hover tint and an accent focus ring. */++:where(input:not([type]),input[type=text],input[type=url],input[type=email],input[type=search],input[type=password],input[type=number],select,textarea){++ padding:10px 12px;background:var(--bg-input);border:1px solid var(--border);border-radius:10px;++ color:var(--text);font:inherit;font-size:13px;outline:none;min-height:40px;++ transition:border-color .18s ease,box-shadow .18s ease,background-color .18s ease;++}++:where(input:not([type]),input[type=text],input[type=url],input[type=email],input[type=search],input[type=password],input[type=number],select,textarea):hover{border-color:color-mix(in srgb,var(--accent) 40%,var(--border))}++:where(input:not([type]),input[type=text],input[type=url],input[type=email],input[type=search],input[type=password],input[type=number],select,textarea):focus{++ border-color:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 24%,transparent);++ background:color-mix(in srgb,var(--accent) 5%,var(--bg-input));++}++:where(input,textarea)::placeholder{color:var(--text-muted);opacity:1}++:where(input,select,textarea):user-invalid{border-color:var(--danger,#ef4444)}++.form-field input,.form-field select,.form-field textarea{width:100%}.form-field textarea{resize:vertical;min-height:60px}.form-field .hint{font-size:10px;color:var(--text-muted);margin-top:3px}++.theme-submit{display:grid;grid-template-columns:repeat(2,minmax(0,1fr)) auto;gap:12px;align-items:start;margin-top:16px}++.theme-submit .form-field{margin:0}++.theme-submit .btn{margin-top:21px;min-height:40px}++@media (max-width:640px){.theme-submit{grid-template-columns:1fr}.theme-submit .btn{margin-top:0}}.btn{padding:8px 20px;border:none;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer;transition:all .15s;}--.btn-primary{background:var(--accent);color:#fff}++.btn-primary{background:var(--accent);color:var(--on-accent,#fff)}.btn-primary:hover{background:var(--accent-dark)}.btn-outline{background:transparent;border:1px solid var(--border);color:var(--text)}.btn-outline:hover{border-color:var(--accent-dark);color:var(--accent-light)}@@@ -384,9 +397,9 @@ a.linked-item:hover{background:var(--bg-hover,var(--bg-card));transform:translat<button class="btn btn-outline" onclick="exportActiveTheme(this)"><i class="fa-solid fa-file-export"></i> Export active theme</button><label class="btn btn-outline" style="cursor:pointer"><i class="fa-solid fa-file-import"></i> Import a theme file<input type="file" accept=".json,application/json" onchange="importThemeFile(this)" style="display:none"></label></div>-- <form onsubmit="submitMyTheme(event)" style="display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end;margin-top:14px">-- <label style="display:grid;gap:4px;font-size:0.85rem">Name<input id="theme-submit-name" required minlength="2" maxlength="60" style="min-width:180px"></label>-- <label style="display:grid;gap:4px;font-size:0.85rem">Address (lowercase, hyphens)<input id="theme-submit-slug" required pattern="[a-z0-9-]{2,48}" style="min-width:180px"></label>++ <form class="theme-submit" onsubmit="submitMyTheme(event)">++ <div class="form-field"><label for="theme-submit-name">Name</label><input id="theme-submit-name" required minlength="2" maxlength="60" placeholder="Midnight Arcade" autocomplete="off"></div>++ <div class="form-field"><label for="theme-submit-slug">Address</label><input id="theme-submit-slug" required pattern="[a-z0-9-]{2,48}" placeholder="midnight-arcade" autocomplete="off" spellcheck="false"><div class="hint">Lowercase letters, numbers and hyphens</div></div><button class="btn btn-primary" type="submit"><i class="fa-solid fa-paper-plane"></i> Submit my colours</button></form><div id="theme-submissions" style="margin-top:14px"></div>@@@ -587,6 +600,7 @@ const LOCAL_THEME_MAP = {'--text': '--text-primary','--text-secondary': '--text-secondary','--text-muted': '--text-muted',++ '--on-accent': '--on-accent',};function getStoredAccounts() {@@@ -908,6 +922,9 @@ function themePreviewColors(theme) {function applyThemeToPage(theme) {const vars = theme?.variables || {};++ // The shared loader applies every token (the canvas behind the page, --on-accent, the browser UI);++ // this page's own short names follow below.++ if (typeof OpenVibeThemeLoader !== 'undefined' && OpenVibeThemeLoader.applyVars) OpenVibeThemeLoader.applyVars(vars);Object.entries(LOCAL_THEME_MAP).forEach(([localVar, themeVar]) => {const value = vars[themeVar];if (value) document.documentElement.style.setProperty(localVar, value);
@@ -22,7 +22,7 @@
@@ -22,7 +22,7 @@
"multer": "^1.4.5-lts.1",
"multer": "^1.4.5-lts.1",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.76.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.76.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.12.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.12.0",
- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.28.1",
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.29.1",
"uuid": "^11.1.0",
"uuid": "^11.1.0",
"web-push": "^3.6.7"
"web-push": "^3.6.7"
}
}
@@ -1490,9 +1490,9 @@
@@ -1490,9 +1490,9 @@
}
}
},
},
"node_modules/openvibe-shared": {
"node_modules/openvibe-shared": {
- "version": "1.28.1",
- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.28.1",
- "integrity": "sha512-AV39sRi9hm8QETRLM1c6q7nrU8XWPUZzCxZP+h7Cho+LsJ47szHtMk3YdCQHT8+aSC5Hpu68EU8sCvbagR+a0g==",
+ "version": "1.29.1",
+ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.29.1",
+ "integrity": "sha512-HI1aySq1Lipd/GRGI0exL98LVQ2UXWeIlYk3TaTgMsjV/S1L5tTyaI+tNKJ8q8zKpMNdXj0hSflENBE97i/CxQ==",
"license": "MIT",
"license": "MIT",
"dependencies": {
"dependencies": {
"jsonwebtoken": "^9.0.0"
"jsonwebtoken": "^9.0.0"
@@ -25,7 +25,7 @@
@@ -25,7 +25,7 @@
"multer": "^1.4.5-lts.1",
"multer": "^1.4.5-lts.1",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.76.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.76.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.12.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.12.0",
- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.28.1",
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.29.1",
"uuid": "^11.1.0",
"uuid": "^11.1.0",
"web-push": "^3.6.7"
"web-push": "^3.6.7"
}
}
@@ -84,7 +84,7 @@ body{min-height:100%;color:var(--text);font-family:'Inter',-apple-system,BlinkMa
@@ -84,7 +84,7 @@ body{min-height:100%;color:var(--text);font-family:'Inter',-apple-system,BlinkMa
/* Buttons */
/* Buttons */
.btn{padding:8px 16px;border:none;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer;transition:all .15s;display:inline-flex;align-items:center;gap:6px}
.btn{padding:8px 16px;border:none;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer;transition:all .15s;display:inline-flex;align-items:center;gap:6px}
-.btn-primary{background:var(--accent);color:#fff}
+.btn-primary{background:var(--accent);color:var(--on-accent,#fff)}
.btn-primary:hover{background:var(--accent-dark)}
.btn-primary:hover{background:var(--accent-dark)}
.btn-outline{background:transparent;border:1px solid var(--border);color:var(--text)}
.btn-outline{background:transparent;border:1px solid var(--border);color:var(--text)}
.btn-outline:hover{border-color:var(--accent-dark);color:var(--accent-light)}
.btn-outline:hover{border-color:var(--accent-dark);color:var(--accent-light)}
@@ -82,18 +82,31 @@ body{min-height:100%;color:var(--text);font-family:'Inter',-apple-system,BlinkMa
@@ -82,18 +82,31 @@ body{min-height:100%;color:var(--text);font-family:'Inter',-apple-system,BlinkMa
/* Form fields */
/* Form fields */
.form-field{margin-bottom:14px}
.form-field{margin-bottom:14px}
.form-field label{display:block;font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:5px}
.form-field label{display:block;font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:5px}
-.form-field input,.form-field select,.form-field textarea{
- width:100%;padding:10px 12px;background:var(--bg-input);border:1px solid var(--border);
- border-radius:8px;color:var(--text);font-size:13px;outline:none;transition:border-color .2s;
-}
-.form-field input:focus,.form-field select:focus,.form-field textarea:focus{border-color:var(--accent)}
+/* Every text field on the page follows the active theme: its input colour, a hover tint and an accent focus ring. */
+:where(input:not([type]),input[type=text],input[type=url],input[type=email],input[type=search],input[type=password],input[type=number],select,textarea){
+ padding:10px 12px;background:var(--bg-input);border:1px solid var(--border);border-radius:10px;
+ color:var(--text);font:inherit;font-size:13px;outline:none;min-height:40px;
+ transition:border-color .18s ease,box-shadow .18s ease,background-color .18s ease;
+}
+:where(input:not([type]),input[type=text],input[type=url],input[type=email],input[type=search],input[type=password],input[type=number],select,textarea):hover{border-color:color-mix(in srgb,var(--accent) 40%,var(--border))}
+:where(input:not([type]),input[type=text],input[type=url],input[type=email],input[type=search],input[type=password],input[type=number],select,textarea):focus{
+ border-color:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 24%,transparent);
+ background:color-mix(in srgb,var(--accent) 5%,var(--bg-input));
+}
+:where(input,textarea)::placeholder{color:var(--text-muted);opacity:1}
+:where(input,select,textarea):user-invalid{border-color:var(--danger,#ef4444)}
+.form-field input,.form-field select,.form-field textarea{width:100%}
.form-field textarea{resize:vertical;min-height:60px}
.form-field textarea{resize:vertical;min-height:60px}
.form-field .hint{font-size:10px;color:var(--text-muted);margin-top:3px}
.form-field .hint{font-size:10px;color:var(--text-muted);margin-top:3px}
+.theme-submit{display:grid;grid-template-columns:repeat(2,minmax(0,1fr)) auto;gap:12px;align-items:start;margin-top:16px}
+.theme-submit .form-field{margin:0}
+.theme-submit .btn{margin-top:21px;min-height:40px}
+@media (max-width:640px){.theme-submit{grid-template-columns:1fr}.theme-submit .btn{margin-top:0}}
.btn{
.btn{
padding:8px 20px;border:none;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer;transition:all .15s;
padding:8px 20px;border:none;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer;transition:all .15s;
}
}
-.btn-primary{background:var(--accent);color:#fff}
+.btn-primary{background:var(--accent);color:var(--on-accent,#fff)}
.btn-primary:hover{background:var(--accent-dark)}
.btn-primary:hover{background:var(--accent-dark)}
.btn-outline{background:transparent;border:1px solid var(--border);color:var(--text)}
.btn-outline{background:transparent;border:1px solid var(--border);color:var(--text)}
.btn-outline:hover{border-color:var(--accent-dark);color:var(--accent-light)}
.btn-outline:hover{border-color:var(--accent-dark);color:var(--accent-light)}
@@ -384,9 +397,9 @@ a.linked-item:hover{background:var(--bg-hover,var(--bg-card));transform:translat
@@ -384,9 +397,9 @@ a.linked-item:hover{background:var(--bg-hover,var(--bg-card));transform:translat
<button class="btn btn-outline" onclick="exportActiveTheme(this)"><i class="fa-solid fa-file-export"></i> Export active theme</button>
<button class="btn btn-outline" onclick="exportActiveTheme(this)"><i class="fa-solid fa-file-export"></i> Export active theme</button>
<label class="btn btn-outline" style="cursor:pointer"><i class="fa-solid fa-file-import"></i> Import a theme file<input type="file" accept=".json,application/json" onchange="importThemeFile(this)" style="display:none"></label>
<label class="btn btn-outline" style="cursor:pointer"><i class="fa-solid fa-file-import"></i> Import a theme file<input type="file" accept=".json,application/json" onchange="importThemeFile(this)" style="display:none"></label>
</div>
</div>
- <form onsubmit="submitMyTheme(event)" style="display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end;margin-top:14px">
- <label style="display:grid;gap:4px;font-size:0.85rem">Name<input id="theme-submit-name" required minlength="2" maxlength="60" style="min-width:180px"></label>
- <label style="display:grid;gap:4px;font-size:0.85rem">Address (lowercase, hyphens)<input id="theme-submit-slug" required pattern="[a-z0-9-]{2,48}" style="min-width:180px"></label>
+ <form class="theme-submit" onsubmit="submitMyTheme(event)">
+ <div class="form-field"><label for="theme-submit-name">Name</label><input id="theme-submit-name" required minlength="2" maxlength="60" placeholder="Midnight Arcade" autocomplete="off"></div>
+ <div class="form-field"><label for="theme-submit-slug">Address</label><input id="theme-submit-slug" required pattern="[a-z0-9-]{2,48}" placeholder="midnight-arcade" autocomplete="off" spellcheck="false"><div class="hint">Lowercase letters, numbers and hyphens</div></div>
<button class="btn btn-primary" type="submit"><i class="fa-solid fa-paper-plane"></i> Submit my colours</button>
<button class="btn btn-primary" type="submit"><i class="fa-solid fa-paper-plane"></i> Submit my colours</button>
</form>
</form>
<div id="theme-submissions" style="margin-top:14px"></div>
<div id="theme-submissions" style="margin-top:14px"></div>
@@ -587,6 +600,7 @@ const LOCAL_THEME_MAP = {
@@ -587,6 +600,7 @@ const LOCAL_THEME_MAP = {
'--text': '--text-primary',
'--text': '--text-primary',
'--text-secondary': '--text-secondary',
'--text-secondary': '--text-secondary',
'--text-muted': '--text-muted',
'--text-muted': '--text-muted',
+ '--on-accent': '--on-accent',
};
};
function getStoredAccounts() {
function getStoredAccounts() {
@@ -908,6 +922,9 @@ function themePreviewColors(theme) {
@@ -908,6 +922,9 @@ function themePreviewColors(theme) {
function applyThemeToPage(theme) {
function applyThemeToPage(theme) {
const vars = theme?.variables || {};
const vars = theme?.variables || {};
+ // The shared loader applies every token (the canvas behind the page, --on-accent, the browser UI);
+ // this page's own short names follow below.
+ if (typeof OpenVibeThemeLoader !== 'undefined' && OpenVibeThemeLoader.applyVars) OpenVibeThemeLoader.applyVars(vars);
Object.entries(LOCAL_THEME_MAP).forEach(([localVar, themeVar]) => {
Object.entries(LOCAL_THEME_MAP).forEach(([localVar, themeVar]) => {
const value = vars[themeVar];
const value = vars[themeVar];
if (value) document.documentElement.style.setProperty(localVar, value);
if (value) document.documentElement.style.setProperty(localVar, value);