openvibers/openvibe.shared Commits
4.18.0: the account menu, reviewed (nothing twice, one order, one icon box) (#141)
Changes
@@@ -6,6 +6,27 @@ A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).## Unreleased++## 4.18.0 — 2026-10-28++++- **The account menu, reviewed** (`navbar.js`). The owner, 2026-10-28: "duplicated things … could just be organized++ better … so many icons sizes that aren't consistent … needs a full review". The changes:++ - **Nothing twice.**++ - The balances are left out of the menu's header when the bar shows them (a site's `coins`/`vibes` chips, or++ `wallet: true`).++ - "My Profile" is gone: the name and picture are the profile link.++ - "Seasonal themes" is gone: its switch is on openvibe.network/themes, beside the themes.++ - "Linked Services" is gone (it is in the account page), and so is "Across OpenVibe": the other sites are the++ launcher's and the drawer's.++ - **One order on every site.**++ - First the site's own rows (`before`, its `sections`, then `after`, which now sits with them).++ - Then **You**: Account & settings, Notifications, My channel, History, Ask Vibe, Work together, and Admin for an++ admin or the owner.++ - Then **Display**: Light / Dark / Auto, text size, animations, and Themes ›.++ - Then Sign out.++ - **One icon box.** Every row's glyph keeps its height and sits centred in the same 20 px box, whatever its width++ (an id card is wider than a bell).++ - Rows are 13 px text in 32 px rows, and a link row no longer overflows the menu by its padding.++- **The browser harness on macOS** (`browser-harness.js`): Chrome starts with `--disable-backgrounding-occluded-windows`,`--disable-renderer-backgrounding` and `--disable-background-timer-throttling`, so every page draws and runs its timersas if in front. On macOS a new page counted as an occluded window and painted nothing (the Core Web Vitals test saw no@@@ -2,7 +2,7 @@> Versioned UI, the OpenVibe Frame (the navbar, footer and "shipped" views every site sits in), SEO, legal and release-client packages every OpenVibe site renders.--**Status:** alpha, v4.17.0 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployed++**Status:** alpha, v4.18.0 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployedconsumer installs a tagged release and none keeps a vendored copy([docs/migration-plan.md](docs/migration-plan.md) is done); each repository's `package.json` namesthe tag it pins.@@@ -4,7 +4,7 @@"code": true,"wave": "W2","package": "openvibe-shared",-- "version": "4.17.0",++ "version": "4.18.0","plan": "OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026)","deployed": false,"deployment": "none of its own: a package released as git tags; OpenVibe.Network serves /shared/* from its pinned tag, and a site can serve its own pinned copy (openvibe-shared/serve)",@@@ -313,8 +313,8 @@.openvibe-navbar-dropdown-menu { padding: 6px 8px; }.openvibe-navbar-dropdown-menu a, .openvibe-navbar-dropdown-menu button {-- display: flex; align-items: center; gap: 8px; width: 100%;-- padding: 8px; border-radius: 6px; font-size: 12px; font-weight: 500;++ display: flex; align-items: center; gap: 10px; width: 100%; box-sizing: border-box;++ padding: 7px 8px; border-radius: 8px; font-size: 13px; font-weight: 500;background: none; border: none; color: var(--text-primary, #e0e0e0);cursor: pointer; text-align: left; text-decoration: none;transition: background .12s;@@@ -327,7 +327,13 @@.openvibe-navbar-dropdown-menu .ud-scheme button[aria-pressed="true"] { background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); }.openvibe-navbar-dropdown-menu .ud-scheme button:focus-visible { outline: 2px solid var(--accent, #3b82f6); outline-offset: 1px; }.openvibe-navbar-dropdown-menu .ud-scheme .icon { width: auto; font-size: 13px; }-- .openvibe-navbar-dropdown-menu .icon { width: 18px; text-align: center; font-size: 14px; }++ /* One box for every icon in the menu: a glyph keeps its height and is centred, whatever its width (an id card++ is wider than a bell), so the rows' icons line up and read as one set. */++ .openvibe-navbar-dropdown-menu .icon { width: 20px; height: 16px; font-size: 15px; color: var(--text-secondary, #a8b3c4); }++ .openvibe-navbar-dropdown-menu .icon .ovnav-ic { width: 1.25em !important; height: 1em; }++ .openvibe-navbar-dropdown-menu a:hover .icon, .openvibe-navbar-dropdown-menu button:hover .icon { color: var(--text-primary, #e0e0e0); }++ .openvibe-navbar-dropdown-menu .danger .icon { color: inherit; }++ .openvibe-navbar-dropdown-menu .ud-go { font-size: 16px; font-weight: 700; color: var(--text-muted, #7d8aa0); }.openvibe-navbar .openvibe-network-badge {font-size: 10px; padding: 2px 8px; border-radius: 4px;@@@ -370,17 +376,16 @@'fa-bell': [448, 'M224 11Q210 11 201 20Q192 29 192 43V62Q136 74 101 117Q65 160 64 219V238Q63 310 16 365L8 374Q-5 389 3 408Q12 426 32 427H416Q436 426 445 408Q453 389 440 374L433 365Q385 311 384 238V219Q383 160 347 117Q312 74 256 62V43Q256 29 247 20Q238 11 224 11ZM269 504Q288 485 288 459H224H160Q160 485 179 504Q198 523 224 523Q250 523 269 504Z'],'fa-clock-rotate-left': [512, 'M75 86 41 52 75 86 41 52Q29 41 15 47Q1 52 0 69V179Q2 201 24 203H134Q151 202 156 188Q162 174 151 162L120 131Q174 77 256 75Q338 77 392 131Q446 185 448 267Q446 349 392 403Q338 457 256 459Q194 458 146 425Q135 417 122 419Q110 422 102 433Q94 444 96 456Q99 469 110 477Q173 522 256 523Q328 522 385 488Q443 454 477 396Q511 339 512 267Q511 195 477 138Q443 80 385 46Q328 12 256 11Q203 11 156 31Q110 51 75 86ZM256 139Q234 141 232 163V267Q232 277 239 284L311 356Q328 370 345 356Q359 339 345 322L280 257V163Q278 141 256 139Z'],'fa-coins': [512, 'M512 91Q511 118 474 139Q428 164 351 170Q346 167 340 165Q279 140 192 139Q180 139 168 140L166 139Q129 118 128 91Q130 57 184 34Q238 12 320 11Q402 12 456 34Q510 57 512 91ZM161 172Q176 171 192 171Q239 171 278 180Q318 188 345 202Q383 223 384 251Q384 257 382 263Q374 283 347 298Q347 298 347 298Q347 298 347 298Q347 298 347 298Q347 298 347 298Q346 299 346 299Q346 299 346 299Q319 314 279 322Q240 331 192 331Q100 330 44 302Q41 300 38 299Q1 278 0 251Q1 224 36 204Q71 184 128 176Q144 173 161 172ZM416 251Q414 218 392 198Q435 191 468 177Q493 167 512 152V187Q511 217 468 238Q446 249 416 256Q416 256 416 256Q416 254 416 251ZM384 347Q383 374 346 395Q344 396 342 397Q341 397 340 398Q284 426 192 427Q144 427 105 418Q65 410 38 395Q1 374 0 347V312Q19 327 44 337Q105 362 192 363Q279 362 340 337Q352 332 363 326Q372 321 380 315Q381 314 383 313Q383 312 384 312V315V321V347ZM416 347V315V347V315V289Q445 283 468 273Q493 263 512 248V283Q512 299 497 314Q471 339 416 352Q416 350 416 347ZM192 459Q279 458 340 433Q365 423 384 408V443Q382 477 328 500Q274 522 192 523Q110 522 56 500Q2 477 0 443V408Q19 423 44 433Q105 458 192 459Z'],-- 'fa-id-card': [576, 'M0 107H576H0H576Q575 80 557 62Q539 44 512 43H64Q37 44 19 62Q1 80 0 107ZM0 139V427V139V427Q1 454 19 472Q37 490 64 491H512Q539 490 557 472Q575 454 576 427V139H0ZM64 416Q65 394 80 379Q95 364 117 363H235Q257 364 272 379Q287 394 288 416Q287 426 277 427H75Q65 426 64 416ZM176 203Q212 204 231 235Q249 267 231 299Q212 330 176 331Q140 330 121 299Q103 267 121 235Q140 204 176 203ZM352 219Q353 204 368 203H496Q511 204 512 219Q511 234 496 235H368Q353 234 352 219ZM352 283Q353 268 368 267H496Q511 268 512 283Q511 298 496 299H368Q353 298 352 283ZM352 347Q353 332 368 331H496Q511 332 512 347Q511 362 496 363H368Q353 362 352 347Z'],-- 'fa-link': [640, 'M580 279Q622 234 622 176Q622 119 580 74Q541 37 489 32Q438 28 394 59L392 60Q381 68 379 81Q377 93 385 105Q393 115 405 117Q418 120 429 112L431 111Q456 94 484 96Q513 98 535 119Q558 144 558 176Q558 209 535 233L422 346Q397 369 365 369Q333 369 308 346Q287 324 285 295Q283 267 300 242L301 240Q308 229 306 217Q304 204 293 196Q282 188 270 190Q257 192 249 203L248 205Q217 249 221 301Q225 352 263 391Q308 433 365 433Q423 433 468 391L580 279ZM60 255Q18 300 18 358Q18 415 60 460Q99 497 151 502Q202 506 247 475L248 474Q259 466 261 453Q263 441 256 429Q247 419 235 417Q222 414 211 422L209 423Q184 440 156 438Q127 436 105 415Q82 390 82 358Q82 325 106 301L218 188Q243 165 275 165Q307 165 332 188Q353 210 355 239Q357 267 340 292L339 294Q332 305 334 318Q336 330 347 338Q358 346 370 344Q383 342 391 331L392 329Q423 285 419 233Q415 182 377 143Q332 101 275 101Q217 101 173 143L60 255Z'],'fa-palette': [512, 'M512 267Q512 268 512 268Q512 269 512 270Q511 297 490 314Q470 331 442 331H344Q324 332 310 345Q297 359 296 379Q296 384 297 389Q300 403 307 417Q307 418 308 419Q318 439 320 461Q320 485 305 503Q291 521 267 523Q261 523 256 523Q184 522 127 488Q69 454 35 396Q1 339 0 267Q1 195 35 138Q69 80 127 46Q184 12 256 11Q328 12 385 46Q443 80 477 138Q511 195 512 267ZM128 299Q128 285 119 276Q110 267 96 267Q82 267 73 276Q64 285 64 299Q64 313 73 322Q82 331 96 331Q110 331 119 322Q128 313 128 299ZM128 203Q142 203 151 194Q160 185 160 171Q160 157 151 148Q142 139 128 139Q114 139 105 148Q96 157 96 171Q96 185 105 194Q114 203 128 203ZM288 107Q288 93 279 84Q270 75 256 75Q242 75 233 84Q224 93 224 107Q224 121 233 130Q242 139 256 139Q270 139 279 130Q288 121 288 107ZM384 203Q398 203 407 194Q416 185 416 171Q416 157 407 148Q398 139 384 139Q370 139 361 148Q352 157 352 171Q352 185 361 194Q370 203 384 203Z'],++ 'fa-people-group': [640, 'M72 99Q73 67 100 51Q128 35 156 51Q183 67 184 99Q183 131 156 147Q128 163 100 147Q73 131 72 99ZM64 257Q49 274 48 299Q49 324 64 341V257ZM208 207Q162 249 160 315Q161 367 192 406V427Q192 441 183 450Q174 459 160 459H96Q82 459 73 450Q64 441 64 427V400Q35 386 18 360Q0 333 0 299Q1 251 33 220Q64 188 112 187H144Q181 188 208 207ZM448 427V406V427V406Q479 367 480 315Q478 249 432 207Q459 188 496 187H528Q576 188 607 220Q639 251 640 299Q640 333 622 360Q605 386 576 400V427Q576 441 567 450Q558 459 544 459H480Q466 459 457 450Q448 441 448 427ZM456 99Q457 67 484 51Q512 35 540 51Q567 67 568 99Q567 131 540 147Q512 163 484 147Q457 131 456 99ZM576 257V341V257V341Q592 324 592 299Q592 274 576 257ZM320 43Q356 44 375 75Q393 107 375 139Q356 170 320 171Q284 170 265 139Q247 107 265 75Q284 44 320 43ZM240 315Q241 340 256 357V273Q241 290 240 315ZM384 273V357V273V357Q400 340 400 315Q400 290 384 273ZM448 315Q448 349 430 376Q413 402 384 416V459Q384 473 375 482Q366 491 352 491H288Q274 491 265 482Q256 473 256 459V416Q227 402 210 376Q192 349 192 315Q193 267 225 236Q256 204 304 203H336Q384 204 415 236Q447 267 448 315Z'],'fa-plus': [448, 'M256 91Q256 77 247 68Q238 59 224 59Q210 59 201 68Q192 77 192 91V235H48Q34 235 25 244Q16 253 16 267Q16 281 25 290Q34 299 48 299H192V443Q192 457 201 466Q210 475 224 475Q238 475 247 466Q256 457 256 443V299H400Q414 299 423 290Q432 281 432 267Q432 253 423 244Q414 235 400 235H256V91Z'],'fa-right-from-bracket': [512, 'M378 117 501 240 378 117 501 240Q512 251 512 267Q512 283 501 294L378 417Q368 427 354 427Q340 427 330 417Q320 407 320 393V331H192Q178 331 169 322Q160 313 160 299V235Q160 221 169 212Q178 203 192 203H320V141Q320 127 330 117Q340 107 354 107Q368 107 378 117ZM160 107H96H160H96Q82 107 73 116Q64 125 64 139V395Q64 409 73 418Q82 427 96 427H160Q174 427 183 436Q192 445 192 459Q192 473 183 482Q174 491 160 491H96Q55 490 28 463Q1 436 0 395V139Q1 98 28 71Q55 44 96 43H160Q174 43 183 52Q192 61 192 75Q192 89 183 98Q174 107 160 107Z'],'fa-shield-halved': [512, 'M256 11Q263 11 269 14L458 94Q475 101 485 116Q496 131 496 151Q497 202 479 271Q461 340 414 405Q368 471 282 514Q256 526 230 514Q144 471 98 405Q51 340 33 271Q15 202 16 151Q16 131 27 116Q37 101 54 94L243 14Q249 11 256 11ZM256 78V456V78V456Q324 421 363 367Q401 313 417 256Q432 198 432 152L256 78Z'],'fa-text-height': [576, 'M64 139V107V139V107H128V427H96Q82 427 73 436Q64 445 64 459Q64 473 73 482Q82 491 96 491H224Q238 491 247 482Q256 473 256 459Q256 445 247 436Q238 427 224 427H192V107H256V139Q256 153 265 162Q274 171 288 171Q302 171 311 162Q320 153 320 139V91Q319 71 306 57Q292 44 272 43H160H48Q28 44 14 57Q1 71 0 91V139Q0 153 9 162Q18 171 32 171Q46 171 55 162Q64 153 64 139ZM503 52Q493 43 480 43Q467 43 457 52L393 116Q379 132 386 151Q395 170 416 171H448V363H416Q395 364 386 383Q379 402 393 418L457 482Q467 491 480 491Q493 491 503 482L567 418Q581 402 574 383Q565 364 544 363H512V171H544Q565 170 574 151Q581 132 567 116L503 52Z'],'fa-tower-broadcast': [576, 'M80 55Q64 94 64 139Q64 184 80 223Q85 236 80 247Q75 259 63 265Q50 270 38 265Q26 259 21 247Q0 197 0 139Q0 81 21 31Q26 19 38 14Q50 9 63 13Q75 19 80 30Q85 42 80 55ZM555 31Q576 81 576 139Q576 197 555 247Q550 259 538 264Q526 269 513 265Q501 259 496 248Q491 236 496 223Q512 184 512 139Q512 94 496 55Q491 42 496 31Q501 19 513 13Q526 8 538 13Q550 19 555 31ZM352 139Q350 176 320 194V491Q320 505 311 514Q302 523 288 523Q274 523 265 514Q256 505 256 491V194Q226 176 224 139Q225 112 243 94Q261 76 288 75Q315 76 333 94Q351 112 352 139ZM171 88Q160 111 160 139Q160 167 171 190Q176 203 171 215Q166 227 154 232Q141 237 130 233Q118 228 112 216Q96 180 96 139Q96 98 112 62Q118 50 130 45Q142 41 154 46Q166 51 171 63Q176 75 171 88ZM464 62Q480 98 480 139Q480 180 464 216Q458 228 446 233Q434 237 422 232Q410 227 405 215Q400 203 405 190Q416 167 416 139Q416 111 405 88Q400 75 405 63Q410 51 422 46Q435 41 446 45Q458 50 464 62Z'],-- 'fa-user': [448, 'M224 267Q259 267 288 250Q317 233 335 203Q352 173 352 139Q352 105 335 75Q317 45 288 28Q259 11 224 11Q189 11 160 28Q131 45 113 75Q96 105 96 139Q96 173 113 203Q131 233 160 250Q189 267 224 267ZM178 315Q103 317 52 367Q2 418 0 493Q0 506 9 514Q17 523 30 523H418Q431 523 439 514Q448 506 448 493Q446 418 396 367Q345 317 270 315H178Z'],'fa-user-secret': [448, 'M224 27Q215 26 209 21Q208 21 208 21Q201 13 176 11Q153 12 137 39Q120 65 110 100Q74 107 53 117Q32 127 32 139Q35 161 97 175Q96 181 96 187Q96 213 105 235H45Q33 236 32 248Q32 251 33 253L72 350Q39 375 20 412Q0 449 0 493Q0 506 9 514Q17 523 30 523H418Q431 523 439 514Q448 506 448 493Q448 449 428 412Q409 375 376 350L415 253Q416 251 416 248Q415 236 403 235H343Q352 213 352 187Q352 181 351 175Q413 161 416 139Q416 127 395 117Q374 107 338 100Q328 65 311 39Q295 12 272 11Q247 13 240 21Q240 21 240 21Q239 21 239 21Q233 26 224 27ZM280 235H268H280H268Q241 234 231 209Q229 204 224 204Q219 204 217 209Q207 234 181 235H168Q151 235 140 223Q128 212 128 195V181Q171 187 224 187Q277 187 320 181V195Q320 212 308 223Q297 235 280 235ZM192 331 208 363 192 331 208 363 176 491 128 299 192 331ZM320 299 272 491 320 299 272 491 240 363 256 331 320 299Z'],'fa-wand-magic-sparkles': [576, 'M235 54 197 68 235 54 197 68Q192 70 192 75Q192 80 197 82L235 96L249 134Q251 139 256 139Q261 139 263 134L277 96L315 82Q320 80 320 75Q320 70 315 68L277 54L263 16Q261 11 256 11Q251 11 249 16L235 54ZM46 406Q32 421 32 440Q32 459 46 474L81 509Q95 523 115 523Q134 523 149 509L530 128Q544 113 544 94Q544 74 530 60L495 25Q481 11 461 11Q442 11 427 25L46 406ZM485 94 380 199 485 94 380 199 356 175 461 70 485 94ZM8 128Q0 131 0 139Q0 147 8 150L64 171L85 228Q88 235 96 235Q104 235 107 228L128 171L185 150Q192 147 192 139Q192 131 185 128L128 107L107 51Q104 43 96 43Q88 43 85 51L64 107L8 128ZM360 384Q352 387 352 395Q352 403 360 406L416 427L437 484Q440 491 448 491Q456 491 459 484L480 427L537 406Q544 403 544 395Q544 387 537 384L480 363L459 307Q456 299 448 299Q440 299 437 307L416 363L360 384Z'],++ 'fa-gear': [512, 'M496 178Q500 192 490 202L446 242Q448 254 448 267Q448 280 446 292L490 332Q500 342 496 356Q489 374 480 391L475 399Q465 415 453 430Q443 441 429 437L373 419Q353 435 329 444L317 502Q313 516 298 519Q278 523 256 523Q234 523 213 519Q199 516 195 502L183 444Q159 435 139 419L83 437Q69 441 59 430Q46 415 37 399L32 391Q23 374 16 357Q12 342 22 332L66 293Q64 280 64 267Q64 254 66 242L22 202Q12 192 16 178Q23 160 32 143L37 135Q46 119 59 104Q69 93 83 97L139 115Q159 99 183 89L195 32Q199 18 214 15Q234 11 256 11Q278 11 299 15Q313 18 317 32L329 89Q353 99 373 115L429 97Q443 93 453 104Q466 119 476 135L480 143Q489 160 496 178ZM256 347Q301 346 325 307Q347 267 325 227Q301 188 256 187Q211 188 187 227Q165 267 187 307Q211 346 256 347Z'],'fa-circle-half-stroke': [512, 'M448 267Q446 185 392 131Q338 77 256 75V459Q338 457 392 403Q446 349 448 267ZM0 267Q1 197 34 139Q68 81 128 45Q189 11 256 11Q323 11 384 45Q444 81 478 139Q511 197 512 267Q511 337 478 395Q444 453 384 489Q323 523 256 523Q189 523 128 489Q68 453 34 395Q1 337 0 267Z'],'fa-moon': [384, 'M224 43Q161 44 111 74Q60 103 30 154Q1 204 0 267Q1 330 31 380Q60 431 111 460Q161 490 224 491Q317 489 379 428Q387 419 382 409Q377 399 365 400Q351 403 335 403Q261 401 211 351Q162 302 160 227Q160 177 184 137Q209 97 249 74Q259 68 257 56Q254 46 242 44Q233 43 223 43Z'],'fa-sun': [512, 'M362 12Q369 16 371 24L391 132L499 152Q507 154 511 161Q514 169 509 177L447 267L509 357Q514 365 511 373Q507 380 499 382L391 402L371 510Q369 518 362 522Q354 525 346 520L256 458L166 520Q158 525 151 522Q143 518 141 510L121 402L13 382Q5 380 1 373Q-2 365 3 357L65 267L3 177Q-2 169 1 162Q5 154 13 152L121 132L141 24Q143 16 151 12Q158 9 166 14L256 76L346 14Q354 9 362 12ZM160 267Q160 241 173 219Q186 197 208 184Q231 171 256 171Q281 171 304 184Q326 197 339 219Q352 241 352 267Q352 293 339 315Q326 337 304 350Q281 363 256 363Q231 363 208 350Q186 337 173 315Q160 293 160 267ZM384 267Q384 232 367 203Q350 174 320 156Q290 139 256 139Q222 139 192 156Q162 174 145 203Q128 232 128 267Q128 302 145 331Q162 360 192 378Q222 395 256 395Q290 395 320 378Q350 360 367 331Q384 302 384 267Z'],@@@ -390,10 +395,10 @@const NAV_ICONS_LAZY = {320: 'fa-chevron-right',384: 'fa-xmark fa-arrow-down fa-play fa-plug fa-file-lines fa-location-dot',-- 448: 'fa-book fa-hand-fist fa-bars fa-arrow-right fa-check fa-tag fa-bolt fa-font fa-lock fa-utensils',-- 512: 'fa-camera fa-gauge-high fa-list-check fa-paste fa-scissors fa-screwdriver-wrench fa-wallet fa-arrow-up-right-from-square fa-chevron-down fa-magnifying-glass fa-gear fa-file-pdf fa-clock fa-envelope fa-heart fa-circle-info fa-triangle-exclamation fa-globe fa-toolbox fa-comment-dots fa-server fa-newspaper fa-chart-line fa-pen-nib fa-key fa-satellite-dish fa-microchip fa-circle-nodes fa-download fa-upload fa-image fa-music',-- 576: 'fa-house fa-video fa-star fa-tower-cell fa-diagram-project fa-money-bill-wave fa-crown fa-ticket fa-map',-- 640: 'fa-comments fa-gamepad fa-network-wired fa-people-arrows fa-people-group fa-shirt fa-code fa-robot fa-photo-film fa-wave-square fa-user-shield',++ 448: 'fa-book fa-hand-fist fa-user fa-bars fa-arrow-right fa-check fa-tag fa-bolt fa-font fa-lock fa-utensils',++ 512: 'fa-camera fa-gauge-high fa-list-check fa-paste fa-scissors fa-screwdriver-wrench fa-wallet fa-arrow-up-right-from-square fa-chevron-down fa-magnifying-glass fa-file-pdf fa-clock fa-envelope fa-heart fa-circle-info fa-triangle-exclamation fa-globe fa-toolbox fa-comment-dots fa-server fa-newspaper fa-chart-line fa-pen-nib fa-key fa-satellite-dish fa-microchip fa-circle-nodes fa-download fa-upload fa-image fa-music',++ 576: 'fa-house fa-id-card fa-video fa-star fa-tower-cell fa-diagram-project fa-money-bill-wave fa-crown fa-ticket fa-map',++ 640: 'fa-comments fa-gamepad fa-link fa-network-wired fa-people-arrows fa-shirt fa-code fa-robot fa-photo-film fa-wave-square fa-user-shield',};const NAV_ICONS_REV = 'bb866b6e2cf3'; // sha256(nav-icons.js), first 12 hex: its ?v= (cacheable forever)// END generated@@@ -891,14 +896,6 @@}/** Sites in the user menu: most used first (Frame data), never the one we are on. */-- function acrossHTML() {-- const frame = OVFrame.get();-- const here = currentHost().toLowerCase();-- const list = (frame && frame.nav.length ? frame.nav.map(n => ({ name: n.name, url: n.url, icon: n.icon || n.id })) : LAUNCHER_SITES)-- .filter(n => { try { const h = new URL(n.url).hostname; return h !== here && !here.endsWith('.' + h); } catch { return false; } }).slice(0, 5);-- return list.map(n => `<a href="${escapeAttr(n.url)}"><span class="icon"><span class="ov-icon" data-icon="${escapeAttr(n.icon)}" data-size="20" data-fx="none"></span></span> ${escapeAttr(n.name)}</a>`).join('');-- }--/** Light / Dark / Auto: the theme's other half, or the device's (theme-loader.js scheme). */function bindScheme(scope) {const L = root.OpenVibeThemeLoader, box = scope.querySelector('.ud-scheme');@@@ -923,7 +920,9 @@/** OpenCoins (Network) and Vibes (OpenVibe.Billing) in the menu header: one request each when the menu first opens. */let _walletLoaded = false;async function loadWallet(dropdown) {-- if (_walletLoaded || !_config.token || (_config.menu && _config.menu.headerChips)) return; _walletLoaded = true;++ // The bar's chips (a site's own, or wallet: true) show the balances already: the menu does not ask twice.++ const inBar = !!_config.wallet || (Array.isArray(_config.chips) && _config.chips.some(c => c && (c.id === 'coins' || c.id === 'vibes')));++ if (_walletLoaded || !_config.token || inBar || (_config.menu && _config.menu.headerChips)) return; _walletLoaded = true;const auth = { Authorization: `Bearer ${_config.token}` };const chip = (id, html) => { const el = dropdown.querySelector(id); if (el) { el.innerHTML = html; el.hidden = false; } };const coins = fetch(`${_config.apiBase}/api/coins/me`, { headers: auth, credentials: 'include' }).then(async (r) => {@@@ -1680,6 +1679,9 @@const menuCfg = _config.menu || {};const before = ((_config.menu && _config.menu.before) || []).concat(_runtimeMenu.before);const after = ((_config.menu && _config.menu.after) || []).concat(_runtimeMenu.after);++ // The bar shows the balances (a site's chips, or wallet: true): the menu does not repeat them.++ const barWallet = !!_config.wallet || (Array.isArray(_config.chips) && _config.chips.some(c => c && (c.id === 'coins' || c.id === 'vibes')));++ const admin = u.role === 'admin' || !!(u.capabilities && (u.capabilities.is_owner || u.capabilities.admin_panel));dropdown.innerHTML = `<div class="openvibe-navbar-dropdown-header">@@@ -1687,7 +1689,7 @@<div class="info"><a class="name ud-me" href="${escapeAttr(meHref)}" title="${isAnon ? 'Your account' : 'Your profile'}">${escapeHtml(u.display_name || u.username)}</a><div class="email">${isAnon ? '' : '@' + escapeHtml(u.username || '')}</div>-- ${menuCfg.headerChips ? `<div class="ud-chips">${chipsHTML(menuCfg.headerChips, 'ovnav-chip ovnav-chip--menu')}</div>` : '<div class="ud-wallet" id="openvibe-wallet" hidden></div><div class="ud-wallet ud-vibes" id="openvibe-vibes" hidden></div>'}++ ${barWallet ? '' : menuCfg.headerChips ? `<div class="ud-chips">${chipsHTML(menuCfg.headerChips, 'ovnav-chip ovnav-chip--menu')}</div>` : '<div class="ud-wallet" id="openvibe-wallet" hidden></div><div class="ud-wallet ud-vibes" id="openvibe-vibes" hidden></div>'}${isAnon ? `<div class="anon-tag">Anonymous #${u.anon_number || '?'}</div>` : ''}</div></div>@@@ -1710,27 +1712,20 @@<div class="openvibe-navbar-dropdown-menu">${before.length ? `<div class="ud-label">${escapeAttr((_config.menu && _config.menu.label) || brand.short || 'This site')}</div>${before.map(menuItemHTML).join('')}<div class="sep"></div>` : ''}${sectionsHTML(menuCfg.sections)}++ ${after.length ? `${after.map(menuItemHTML).join('')}<div class="sep"></div>` : ''}${menuCfg.defaults === false ? '' : `<div class="ud-label">You</div>-- <a href="https://openvibe.network/my"><span class="icon">${navIcon('fa-user')}</span> My Account</a>-- ${!isAnon && u.username ? `<a href="https://openvibe.network/@${escapeAttr(u.username)}"><span class="icon">${navIcon('fa-id-card')}</span> My Profile</a>` : ''}-- ${!isAnon && u.username ? `<a href="https://openvibe.live/@${escapeAttr(u.username)}"><span class="icon">${navIcon('fa-tower-broadcast')}</span> My Channel</a>` : ''}++ <a href="https://openvibe.network/my"><span class="icon">${navIcon('fa-gear')}</span> Account & settings</a><a href="https://openvibe.network/my#notifications"><span class="icon">${navIcon('fa-bell')}</span> Notifications</a>-- ${!isAnon ? `<a href="https://openvibe.chat/vibe" data-ov-ask><span class="icon">${navIcon('fa-brain')}</span> Ask Vibe</a><a href="https://openvibe.chat/work" data-ov-work><span class="icon">${navIcon('fa-plus')}</span> Work together</a>` : ''}++ ${!isAnon && u.username ? `<a href="https://openvibe.live/@${escapeAttr(u.username)}"><span class="icon">${navIcon('fa-tower-broadcast')}</span> My channel</a>` : ''}++ <a href="https://openvibe.network/my#history"><span class="icon">${navIcon('fa-clock-rotate-left')}</span> History</a>++ ${!isAnon ? `<a href="https://openvibe.chat/vibe" data-ov-ask><span class="icon">${navIcon('fa-brain')}</span> Ask Vibe</a><a href="https://openvibe.chat/work" data-ov-work><span class="icon">${navIcon('fa-people-group')}</span> Work together</a>` : ''}++ ${admin ? `<a href="https://openvibe.network/admin"><span class="icon">${navIcon('fa-shield-halved')}</span> Admin</a>` : ''}<div class="sep"></div>`}<div class="ud-label">Display</div><div class="ud-scheme" role="group" aria-label="Light or dark" hidden><button type="button" data-ov-scheme="light" aria-pressed="false"><span class="icon">${navIcon('fa-sun')}</span> Light</button><button type="button" data-ov-scheme="dark" aria-pressed="false"><span class="icon">${navIcon('fa-moon')}</span> Dark</button><button type="button" data-ov-scheme="auto" aria-pressed="false" title="Follow this device's light or dark setting"><span class="icon">${navIcon('fa-circle-half-stroke')}</span> Auto</button></div><button type="button" data-ov-display="text"><span class="icon">${navIcon('fa-text-height')}</span> Text size <b class="ud-val"></b></button><button type="button" data-ov-display="motion"><span class="icon">${navIcon('fa-wand-magic-sparkles')}</span> Animations <b class="ud-val"></b></button>-- <button type="button" data-ov-display="seasonal"><span class="icon">${navIcon('fa-palette')}</span> Seasonal themes <b class="ud-val"></b></button>-- <a href="https://openvibe.network/themes"><span class="icon">${navIcon('fa-palette')}</span> Themes</a>-- <div class="sep"></div>-- <div class="ud-label">Across OpenVibe</div>-- ${acrossHTML()}-- ${menuCfg.defaults === false ? '' : `-- <a href="https://openvibe.network/my#history"><span class="icon">${navIcon('fa-clock-rotate-left')}</span> History</a>-- <a href="https://openvibe.network/my#linked"><span class="icon">${navIcon('fa-link')}</span> Linked Services</a>-- ${u.role === 'admin' ? `<a href="https://openvibe.network/admin"><span class="icon">${navIcon('fa-shield-halved')}</span> Admin Panel</a>` : ''}`}-- ${after.length ? '<div class="sep"></div>' : ''}${after.map(menuItemHTML).join('')}++ <a href="https://openvibe.network/themes" title="Every theme, and the season's own"><span class="icon">${navIcon('fa-palette')}</span> Themes <b class="ud-val ud-go" aria-hidden="true">›</b></a><div class="sep"></div><button id="openvibe-logout-btn" class="danger"><span class="icon">${navIcon('fa-right-from-bracket')}</span> Sign Out</button></div>@@@ -1,6 +1,6 @@{"name": "openvibe-shared",-- "version": "4.17.0",++ "version": "4.18.0","description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site","main": "index.js","bin": {@@@ -230,7 +230,13 @@ function load(hostname, opts = {}) {const dd = created.find(e => e.tag === 'div' && /openvibe-navbar-dropdown-menu/.test(e.innerHTML));assert.ok(dd && dd.innerHTML.includes('data-menu-id="mp"') && dd.innerHTML.includes('My pastes'), 'custom dropdown row rendered');assert.ok(dd.innerHTML.includes('/my#history'), 'History link present');-- assert.ok(dd.innerHTML.includes('href="https://openvibe.network/@x"') && dd.innerHTML.includes('My Profile'), 'the public profile (openvibe.network/@username) is one tap from the account menu');++ assert.ok(dd.innerHTML.includes('href="https://openvibe.network/@x"') && !dd.innerHTML.includes('My Profile'), 'the public profile (openvibe.network/@username) is one tap away: the name and picture, not a row that repeats them');++ // The account menu, reviewed (the owner, 2026-10-28: "duplicated things … so many icons sizes that aren't consistent"):++ // no row says what another says, the seasonal switch is on the Themes page, and every icon sits in one box.++ ['Seasonal themes', 'Linked Services', 'Switch account'].forEach((gone) => assert.ok(!dd.innerHTML.includes(gone), `no "${gone}" row`));++ assert.ok(dd.innerHTML.includes('Account & settings') && dd.innerHTML.includes(' Themes <b class="ud-val ud-go"'), 'one row for the account, one for the themes');++ assert.ok(!dd.innerHTML.includes('Across OpenVibe'), 'the other sites are the launcher\'s and the drawer\'s, not the account menu\'s');++ assert.ok(/\.openvibe-navbar-dropdown-menu \.icon \.ovnav-ic \{ width: 1\.25em !important; height: 1em; \}/.test(require('fs').readFileSync(require('path').join(__dirname, '..', 'navbar.js'), 'utf8')), 'every menu icon in one fixed-width box');assert.ok(dd.innerHTML.includes('<a class="name ud-me" href="https://openvibe.network/@x"'), 'pressing your name in the menu opens your profile');assert.ok(['light', 'dark', 'auto'].every((m) => dd.innerHTML.includes(`data-ov-scheme="${m}"`)) && dd.innerHTML.includes('aria-label="Light or dark"'), 'Light, Dark and Auto are one press away in the account menu');assert.ok(dd.innerHTML.includes('<a class="ud-me" href="https://openvibe.network/@x" tabindex="-1" aria-hidden="true"><img'), 'and so does your picture (one stop for keyboards)');@@@ -48,10 +48,15 @@ function dropdown() {assert.strictEqual(d.els['#openvibe-wallet'].hidden, false);assert.strictEqual(d.els['#openvibe-vibes'].hidden, true, 'no shadow balance');-- // A site with its own header chips (Live) and a signed-out page ask nothing.++ // A site with its own header chips (Live), a bar that shows the balances already, and a signed-out page ask nothing.calls.length = 0;configure({ token: 'tok', menu: { headerChips: [] } });await loadWallet(dropdown());++ configure({ token: 'tok', menu: null, wallet: true });++ await loadWallet(dropdown());++ configure({ token: 'tok', menu: null, wallet: false, chips: [{ id: 'coins', value: '1' }] });++ await loadWallet(dropdown());++ configure({ chips: [] });configure({ token: null, menu: null });await loadWallet(dropdown());assert.strictEqual(calls.length, 0);
@@ -6,6 +6,27 @@ A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).
@@ -6,6 +6,27 @@ A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).
## Unreleased
## Unreleased
+## 4.18.0 — 2026-10-28
+
+- **The account menu, reviewed** (`navbar.js`). The owner, 2026-10-28: "duplicated things … could just be organized
+ better … so many icons sizes that aren't consistent … needs a full review". The changes:
+ - **Nothing twice.**
+ - The balances are left out of the menu's header when the bar shows them (a site's `coins`/`vibes` chips, or
+ `wallet: true`).
+ - "My Profile" is gone: the name and picture are the profile link.
+ - "Seasonal themes" is gone: its switch is on openvibe.network/themes, beside the themes.
+ - "Linked Services" is gone (it is in the account page), and so is "Across OpenVibe": the other sites are the
+ launcher's and the drawer's.
+ - **One order on every site.**
+ - First the site's own rows (`before`, its `sections`, then `after`, which now sits with them).
+ - Then **You**: Account & settings, Notifications, My channel, History, Ask Vibe, Work together, and Admin for an
+ admin or the owner.
+ - Then **Display**: Light / Dark / Auto, text size, animations, and Themes ›.
+ - Then Sign out.
+ - **One icon box.** Every row's glyph keeps its height and sits centred in the same 20 px box, whatever its width
+ (an id card is wider than a bell).
+ - Rows are 13 px text in 32 px rows, and a link row no longer overflows the menu by its padding.
+
- **The browser harness on macOS** (`browser-harness.js`): Chrome starts with `--disable-backgrounding-occluded-windows`,
- **The browser harness on macOS** (`browser-harness.js`): Chrome starts with `--disable-backgrounding-occluded-windows`,
`--disable-renderer-backgrounding` and `--disable-background-timer-throttling`, so every page draws and runs its timers
`--disable-renderer-backgrounding` and `--disable-background-timer-throttling`, so every page draws and runs its timers
as if in front. On macOS a new page counted as an occluded window and painted nothing (the Core Web Vitals test saw no
as if in front. On macOS a new page counted as an occluded window and painted nothing (the Core Web Vitals test saw no
@@ -2,7 +2,7 @@
@@ -2,7 +2,7 @@
> Versioned UI, the OpenVibe Frame (the navbar, footer and "shipped" views every site sits in), SEO, legal and release-client packages every OpenVibe site renders.
> Versioned UI, the OpenVibe Frame (the navbar, footer and "shipped" views every site sits in), SEO, legal and release-client packages every OpenVibe site renders.
-**Status:** alpha, v4.17.0 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployed
+**Status:** alpha, v4.18.0 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployed
consumer installs a tagged release and none keeps a vendored copy
consumer installs a tagged release and none keeps a vendored copy
([docs/migration-plan.md](docs/migration-plan.md) is done); each repository's `package.json` names
([docs/migration-plan.md](docs/migration-plan.md) is done); each repository's `package.json` names
the tag it pins.
the tag it pins.
@@ -4,7 +4,7 @@
@@ -4,7 +4,7 @@
"code": true,
"code": true,
"wave": "W2",
"wave": "W2",
"package": "openvibe-shared",
"package": "openvibe-shared",
- "version": "4.17.0",
+ "version": "4.18.0",
"plan": "OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026)",
"plan": "OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026)",
"deployed": false,
"deployed": false,
"deployment": "none of its own: a package released as git tags; OpenVibe.Network serves /shared/* from its pinned tag, and a site can serve its own pinned copy (openvibe-shared/serve)",
"deployment": "none of its own: a package released as git tags; OpenVibe.Network serves /shared/* from its pinned tag, and a site can serve its own pinned copy (openvibe-shared/serve)",
@@ -313,8 +313,8 @@
@@ -313,8 +313,8 @@
.openvibe-navbar-dropdown-menu { padding: 6px 8px; }
.openvibe-navbar-dropdown-menu { padding: 6px 8px; }
.openvibe-navbar-dropdown-menu a, .openvibe-navbar-dropdown-menu button {
.openvibe-navbar-dropdown-menu a, .openvibe-navbar-dropdown-menu button {
- display: flex; align-items: center; gap: 8px; width: 100%;
- padding: 8px; border-radius: 6px; font-size: 12px; font-weight: 500;
+ display: flex; align-items: center; gap: 10px; width: 100%; box-sizing: border-box;
+ padding: 7px 8px; border-radius: 8px; font-size: 13px; font-weight: 500;
background: none; border: none; color: var(--text-primary, #e0e0e0);
background: none; border: none; color: var(--text-primary, #e0e0e0);
cursor: pointer; text-align: left; text-decoration: none;
cursor: pointer; text-align: left; text-decoration: none;
transition: background .12s;
transition: background .12s;
@@ -327,7 +327,13 @@
@@ -327,7 +327,13 @@
.openvibe-navbar-dropdown-menu .ud-scheme button[aria-pressed="true"] { background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); }
.openvibe-navbar-dropdown-menu .ud-scheme button[aria-pressed="true"] { background: var(--accent-strong, var(--accent, #3472d8)); color: var(--on-accent-strong, var(--on-accent, #fff)); }
.openvibe-navbar-dropdown-menu .ud-scheme button:focus-visible { outline: 2px solid var(--accent, #3b82f6); outline-offset: 1px; }
.openvibe-navbar-dropdown-menu .ud-scheme button:focus-visible { outline: 2px solid var(--accent, #3b82f6); outline-offset: 1px; }
.openvibe-navbar-dropdown-menu .ud-scheme .icon { width: auto; font-size: 13px; }
.openvibe-navbar-dropdown-menu .ud-scheme .icon { width: auto; font-size: 13px; }
- .openvibe-navbar-dropdown-menu .icon { width: 18px; text-align: center; font-size: 14px; }
+ /* One box for every icon in the menu: a glyph keeps its height and is centred, whatever its width (an id card
+ is wider than a bell), so the rows' icons line up and read as one set. */
+ .openvibe-navbar-dropdown-menu .icon { width: 20px; height: 16px; font-size: 15px; color: var(--text-secondary, #a8b3c4); }
+ .openvibe-navbar-dropdown-menu .icon .ovnav-ic { width: 1.25em !important; height: 1em; }
+ .openvibe-navbar-dropdown-menu a:hover .icon, .openvibe-navbar-dropdown-menu button:hover .icon { color: var(--text-primary, #e0e0e0); }
+ .openvibe-navbar-dropdown-menu .danger .icon { color: inherit; }
+ .openvibe-navbar-dropdown-menu .ud-go { font-size: 16px; font-weight: 700; color: var(--text-muted, #7d8aa0); }
.openvibe-navbar .openvibe-network-badge {
.openvibe-navbar .openvibe-network-badge {
font-size: 10px; padding: 2px 8px; border-radius: 4px;
font-size: 10px; padding: 2px 8px; border-radius: 4px;
@@ -370,17 +376,16 @@
@@ -370,17 +376,16 @@
'fa-bell': [448, 'M224 11Q210 11 201 20Q192 29 192 43V62Q136 74 101 117Q65 160 64 219V238Q63 310 16 365L8 374Q-5 389 3 408Q12 426 32 427H416Q436 426 445 408Q453 389 440 374L433 365Q385 311 384 238V219Q383 160 347 117Q312 74 256 62V43Q256 29 247 20Q238 11 224 11ZM269 504Q288 485 288 459H224H160Q160 485 179 504Q198 523 224 523Q250 523 269 504Z'],
'fa-bell': [448, 'M224 11Q210 11 201 20Q192 29 192 43V62Q136 74 101 117Q65 160 64 219V238Q63 310 16 365L8 374Q-5 389 3 408Q12 426 32 427H416Q436 426 445 408Q453 389 440 374L433 365Q385 311 384 238V219Q383 160 347 117Q312 74 256 62V43Q256 29 247 20Q238 11 224 11ZM269 504Q288 485 288 459H224H160Q160 485 179 504Q198 523 224 523Q250 523 269 504Z'],
'fa-clock-rotate-left': [512, 'M75 86 41 52 75 86 41 52Q29 41 15 47Q1 52 0 69V179Q2 201 24 203H134Q151 202 156 188Q162 174 151 162L120 131Q174 77 256 75Q338 77 392 131Q446 185 448 267Q446 349 392 403Q338 457 256 459Q194 458 146 425Q135 417 122 419Q110 422 102 433Q94 444 96 456Q99 469 110 477Q173 522 256 523Q328 522 385 488Q443 454 477 396Q511 339 512 267Q511 195 477 138Q443 80 385 46Q328 12 256 11Q203 11 156 31Q110 51 75 86ZM256 139Q234 141 232 163V267Q232 277 239 284L311 356Q328 370 345 356Q359 339 345 322L280 257V163Q278 141 256 139Z'],
'fa-clock-rotate-left': [512, 'M75 86 41 52 75 86 41 52Q29 41 15 47Q1 52 0 69V179Q2 201 24 203H134Q151 202 156 188Q162 174 151 162L120 131Q174 77 256 75Q338 77 392 131Q446 185 448 267Q446 349 392 403Q338 457 256 459Q194 458 146 425Q135 417 122 419Q110 422 102 433Q94 444 96 456Q99 469 110 477Q173 522 256 523Q328 522 385 488Q443 454 477 396Q511 339 512 267Q511 195 477 138Q443 80 385 46Q328 12 256 11Q203 11 156 31Q110 51 75 86ZM256 139Q234 141 232 163V267Q232 277 239 284L311 356Q328 370 345 356Q359 339 345 322L280 257V163Q278 141 256 139Z'],
'fa-coins': [512, 'M512 91Q511 118 474 139Q428 164 351 170Q346 167 340 165Q279 140 192 139Q180 139 168 140L166 139Q129 118 128 91Q130 57 184 34Q238 12 320 11Q402 12 456 34Q510 57 512 91ZM161 172Q176 171 192 171Q239 171 278 180Q318 188 345 202Q383 223 384 251Q384 257 382 263Q374 283 347 298Q347 298 347 298Q347 298 347 298Q347 298 347 298Q347 298 347 298Q346 299 346 299Q346 299 346 299Q319 314 279 322Q240 331 192 331Q100 330 44 302Q41 300 38 299Q1 278 0 251Q1 224 36 204Q71 184 128 176Q144 173 161 172ZM416 251Q414 218 392 198Q435 191 468 177Q493 167 512 152V187Q511 217 468 238Q446 249 416 256Q416 256 416 256Q416 254 416 251ZM384 347Q383 374 346 395Q344 396 342 397Q341 397 340 398Q284 426 192 427Q144 427 105 418Q65 410 38 395Q1 374 0 347V312Q19 327 44 337Q105 362 192 363Q279 362 340 337Q352 332 363 326Q372 321 380 315Q381 314 383 313Q383 312 384 312V315V321V347ZM416 347V315V347V315V289Q445 283 468 273Q493 263 512 248V283Q512 299 497 314Q471 339 416 352Q416 350 416 347ZM192 459Q279 458 340 433Q365 423 384 408V443Q382 477 328 500Q274 522 192 523Q110 522 56 500Q2 477 0 443V408Q19 423 44 433Q105 458 192 459Z'],
'fa-coins': [512, 'M512 91Q511 118 474 139Q428 164 351 170Q346 167 340 165Q279 140 192 139Q180 139 168 140L166 139Q129 118 128 91Q130 57 184 34Q238 12 320 11Q402 12 456 34Q510 57 512 91ZM161 172Q176 171 192 171Q239 171 278 180Q318 188 345 202Q383 223 384 251Q384 257 382 263Q374 283 347 298Q347 298 347 298Q347 298 347 298Q347 298 347 298Q347 298 347 298Q346 299 346 299Q346 299 346 299Q319 314 279 322Q240 331 192 331Q100 330 44 302Q41 300 38 299Q1 278 0 251Q1 224 36 204Q71 184 128 176Q144 173 161 172ZM416 251Q414 218 392 198Q435 191 468 177Q493 167 512 152V187Q511 217 468 238Q446 249 416 256Q416 256 416 256Q416 254 416 251ZM384 347Q383 374 346 395Q344 396 342 397Q341 397 340 398Q284 426 192 427Q144 427 105 418Q65 410 38 395Q1 374 0 347V312Q19 327 44 337Q105 362 192 363Q279 362 340 337Q352 332 363 326Q372 321 380 315Q381 314 383 313Q383 312 384 312V315V321V347ZM416 347V315V347V315V289Q445 283 468 273Q493 263 512 248V283Q512 299 497 314Q471 339 416 352Q416 350 416 347ZM192 459Q279 458 340 433Q365 423 384 408V443Q382 477 328 500Q274 522 192 523Q110 522 56 500Q2 477 0 443V408Q19 423 44 433Q105 458 192 459Z'],
- 'fa-id-card': [576, 'M0 107H576H0H576Q575 80 557 62Q539 44 512 43H64Q37 44 19 62Q1 80 0 107ZM0 139V427V139V427Q1 454 19 472Q37 490 64 491H512Q539 490 557 472Q575 454 576 427V139H0ZM64 416Q65 394 80 379Q95 364 117 363H235Q257 364 272 379Q287 394 288 416Q287 426 277 427H75Q65 426 64 416ZM176 203Q212 204 231 235Q249 267 231 299Q212 330 176 331Q140 330 121 299Q103 267 121 235Q140 204 176 203ZM352 219Q353 204 368 203H496Q511 204 512 219Q511 234 496 235H368Q353 234 352 219ZM352 283Q353 268 368 267H496Q511 268 512 283Q511 298 496 299H368Q353 298 352 283ZM352 347Q353 332 368 331H496Q511 332 512 347Q511 362 496 363H368Q353 362 352 347Z'],
- 'fa-link': [640, 'M580 279Q622 234 622 176Q622 119 580 74Q541 37 489 32Q438 28 394 59L392 60Q381 68 379 81Q377 93 385 105Q393 115 405 117Q418 120 429 112L431 111Q456 94 484 96Q513 98 535 119Q558 144 558 176Q558 209 535 233L422 346Q397 369 365 369Q333 369 308 346Q287 324 285 295Q283 267 300 242L301 240Q308 229 306 217Q304 204 293 196Q282 188 270 190Q257 192 249 203L248 205Q217 249 221 301Q225 352 263 391Q308 433 365 433Q423 433 468 391L580 279ZM60 255Q18 300 18 358Q18 415 60 460Q99 497 151 502Q202 506 247 475L248 474Q259 466 261 453Q263 441 256 429Q247 419 235 417Q222 414 211 422L209 423Q184 440 156 438Q127 436 105 415Q82 390 82 358Q82 325 106 301L218 188Q243 165 275 165Q307 165 332 188Q353 210 355 239Q357 267 340 292L339 294Q332 305 334 318Q336 330 347 338Q358 346 370 344Q383 342 391 331L392 329Q423 285 419 233Q415 182 377 143Q332 101 275 101Q217 101 173 143L60 255Z'],
'fa-palette': [512, 'M512 267Q512 268 512 268Q512 269 512 270Q511 297 490 314Q470 331 442 331H344Q324 332 310 345Q297 359 296 379Q296 384 297 389Q300 403 307 417Q307 418 308 419Q318 439 320 461Q320 485 305 503Q291 521 267 523Q261 523 256 523Q184 522 127 488Q69 454 35 396Q1 339 0 267Q1 195 35 138Q69 80 127 46Q184 12 256 11Q328 12 385 46Q443 80 477 138Q511 195 512 267ZM128 299Q128 285 119 276Q110 267 96 267Q82 267 73 276Q64 285 64 299Q64 313 73 322Q82 331 96 331Q110 331 119 322Q128 313 128 299ZM128 203Q142 203 151 194Q160 185 160 171Q160 157 151 148Q142 139 128 139Q114 139 105 148Q96 157 96 171Q96 185 105 194Q114 203 128 203ZM288 107Q288 93 279 84Q270 75 256 75Q242 75 233 84Q224 93 224 107Q224 121 233 130Q242 139 256 139Q270 139 279 130Q288 121 288 107ZM384 203Q398 203 407 194Q416 185 416 171Q416 157 407 148Q398 139 384 139Q370 139 361 148Q352 157 352 171Q352 185 361 194Q370 203 384 203Z'],
'fa-palette': [512, 'M512 267Q512 268 512 268Q512 269 512 270Q511 297 490 314Q470 331 442 331H344Q324 332 310 345Q297 359 296 379Q296 384 297 389Q300 403 307 417Q307 418 308 419Q318 439 320 461Q320 485 305 503Q291 521 267 523Q261 523 256 523Q184 522 127 488Q69 454 35 396Q1 339 0 267Q1 195 35 138Q69 80 127 46Q184 12 256 11Q328 12 385 46Q443 80 477 138Q511 195 512 267ZM128 299Q128 285 119 276Q110 267 96 267Q82 267 73 276Q64 285 64 299Q64 313 73 322Q82 331 96 331Q110 331 119 322Q128 313 128 299ZM128 203Q142 203 151 194Q160 185 160 171Q160 157 151 148Q142 139 128 139Q114 139 105 148Q96 157 96 171Q96 185 105 194Q114 203 128 203ZM288 107Q288 93 279 84Q270 75 256 75Q242 75 233 84Q224 93 224 107Q224 121 233 130Q242 139 256 139Q270 139 279 130Q288 121 288 107ZM384 203Q398 203 407 194Q416 185 416 171Q416 157 407 148Q398 139 384 139Q370 139 361 148Q352 157 352 171Q352 185 361 194Q370 203 384 203Z'],
+ 'fa-people-group': [640, 'M72 99Q73 67 100 51Q128 35 156 51Q183 67 184 99Q183 131 156 147Q128 163 100 147Q73 131 72 99ZM64 257Q49 274 48 299Q49 324 64 341V257ZM208 207Q162 249 160 315Q161 367 192 406V427Q192 441 183 450Q174 459 160 459H96Q82 459 73 450Q64 441 64 427V400Q35 386 18 360Q0 333 0 299Q1 251 33 220Q64 188 112 187H144Q181 188 208 207ZM448 427V406V427V406Q479 367 480 315Q478 249 432 207Q459 188 496 187H528Q576 188 607 220Q639 251 640 299Q640 333 622 360Q605 386 576 400V427Q576 441 567 450Q558 459 544 459H480Q466 459 457 450Q448 441 448 427ZM456 99Q457 67 484 51Q512 35 540 51Q567 67 568 99Q567 131 540 147Q512 163 484 147Q457 131 456 99ZM576 257V341V257V341Q592 324 592 299Q592 274 576 257ZM320 43Q356 44 375 75Q393 107 375 139Q356 170 320 171Q284 170 265 139Q247 107 265 75Q284 44 320 43ZM240 315Q241 340 256 357V273Q241 290 240 315ZM384 273V357V273V357Q400 340 400 315Q400 290 384 273ZM448 315Q448 349 430 376Q413 402 384 416V459Q384 473 375 482Q366 491 352 491H288Q274 491 265 482Q256 473 256 459V416Q227 402 210 376Q192 349 192 315Q193 267 225 236Q256 204 304 203H336Q384 204 415 236Q447 267 448 315Z'],
'fa-plus': [448, 'M256 91Q256 77 247 68Q238 59 224 59Q210 59 201 68Q192 77 192 91V235H48Q34 235 25 244Q16 253 16 267Q16 281 25 290Q34 299 48 299H192V443Q192 457 201 466Q210 475 224 475Q238 475 247 466Q256 457 256 443V299H400Q414 299 423 290Q432 281 432 267Q432 253 423 244Q414 235 400 235H256V91Z'],
'fa-plus': [448, 'M256 91Q256 77 247 68Q238 59 224 59Q210 59 201 68Q192 77 192 91V235H48Q34 235 25 244Q16 253 16 267Q16 281 25 290Q34 299 48 299H192V443Q192 457 201 466Q210 475 224 475Q238 475 247 466Q256 457 256 443V299H400Q414 299 423 290Q432 281 432 267Q432 253 423 244Q414 235 400 235H256V91Z'],
'fa-right-from-bracket': [512, 'M378 117 501 240 378 117 501 240Q512 251 512 267Q512 283 501 294L378 417Q368 427 354 427Q340 427 330 417Q320 407 320 393V331H192Q178 331 169 322Q160 313 160 299V235Q160 221 169 212Q178 203 192 203H320V141Q320 127 330 117Q340 107 354 107Q368 107 378 117ZM160 107H96H160H96Q82 107 73 116Q64 125 64 139V395Q64 409 73 418Q82 427 96 427H160Q174 427 183 436Q192 445 192 459Q192 473 183 482Q174 491 160 491H96Q55 490 28 463Q1 436 0 395V139Q1 98 28 71Q55 44 96 43H160Q174 43 183 52Q192 61 192 75Q192 89 183 98Q174 107 160 107Z'],
'fa-right-from-bracket': [512, 'M378 117 501 240 378 117 501 240Q512 251 512 267Q512 283 501 294L378 417Q368 427 354 427Q340 427 330 417Q320 407 320 393V331H192Q178 331 169 322Q160 313 160 299V235Q160 221 169 212Q178 203 192 203H320V141Q320 127 330 117Q340 107 354 107Q368 107 378 117ZM160 107H96H160H96Q82 107 73 116Q64 125 64 139V395Q64 409 73 418Q82 427 96 427H160Q174 427 183 436Q192 445 192 459Q192 473 183 482Q174 491 160 491H96Q55 490 28 463Q1 436 0 395V139Q1 98 28 71Q55 44 96 43H160Q174 43 183 52Q192 61 192 75Q192 89 183 98Q174 107 160 107Z'],
'fa-shield-halved': [512, 'M256 11Q263 11 269 14L458 94Q475 101 485 116Q496 131 496 151Q497 202 479 271Q461 340 414 405Q368 471 282 514Q256 526 230 514Q144 471 98 405Q51 340 33 271Q15 202 16 151Q16 131 27 116Q37 101 54 94L243 14Q249 11 256 11ZM256 78V456V78V456Q324 421 363 367Q401 313 417 256Q432 198 432 152L256 78Z'],
'fa-shield-halved': [512, 'M256 11Q263 11 269 14L458 94Q475 101 485 116Q496 131 496 151Q497 202 479 271Q461 340 414 405Q368 471 282 514Q256 526 230 514Q144 471 98 405Q51 340 33 271Q15 202 16 151Q16 131 27 116Q37 101 54 94L243 14Q249 11 256 11ZM256 78V456V78V456Q324 421 363 367Q401 313 417 256Q432 198 432 152L256 78Z'],
'fa-text-height': [576, 'M64 139V107V139V107H128V427H96Q82 427 73 436Q64 445 64 459Q64 473 73 482Q82 491 96 491H224Q238 491 247 482Q256 473 256 459Q256 445 247 436Q238 427 224 427H192V107H256V139Q256 153 265 162Q274 171 288 171Q302 171 311 162Q320 153 320 139V91Q319 71 306 57Q292 44 272 43H160H48Q28 44 14 57Q1 71 0 91V139Q0 153 9 162Q18 171 32 171Q46 171 55 162Q64 153 64 139ZM503 52Q493 43 480 43Q467 43 457 52L393 116Q379 132 386 151Q395 170 416 171H448V363H416Q395 364 386 383Q379 402 393 418L457 482Q467 491 480 491Q493 491 503 482L567 418Q581 402 574 383Q565 364 544 363H512V171H544Q565 170 574 151Q581 132 567 116L503 52Z'],
'fa-text-height': [576, 'M64 139V107V139V107H128V427H96Q82 427 73 436Q64 445 64 459Q64 473 73 482Q82 491 96 491H224Q238 491 247 482Q256 473 256 459Q256 445 247 436Q238 427 224 427H192V107H256V139Q256 153 265 162Q274 171 288 171Q302 171 311 162Q320 153 320 139V91Q319 71 306 57Q292 44 272 43H160H48Q28 44 14 57Q1 71 0 91V139Q0 153 9 162Q18 171 32 171Q46 171 55 162Q64 153 64 139ZM503 52Q493 43 480 43Q467 43 457 52L393 116Q379 132 386 151Q395 170 416 171H448V363H416Q395 364 386 383Q379 402 393 418L457 482Q467 491 480 491Q493 491 503 482L567 418Q581 402 574 383Q565 364 544 363H512V171H544Q565 170 574 151Q581 132 567 116L503 52Z'],
'fa-tower-broadcast': [576, 'M80 55Q64 94 64 139Q64 184 80 223Q85 236 80 247Q75 259 63 265Q50 270 38 265Q26 259 21 247Q0 197 0 139Q0 81 21 31Q26 19 38 14Q50 9 63 13Q75 19 80 30Q85 42 80 55ZM555 31Q576 81 576 139Q576 197 555 247Q550 259 538 264Q526 269 513 265Q501 259 496 248Q491 236 496 223Q512 184 512 139Q512 94 496 55Q491 42 496 31Q501 19 513 13Q526 8 538 13Q550 19 555 31ZM352 139Q350 176 320 194V491Q320 505 311 514Q302 523 288 523Q274 523 265 514Q256 505 256 491V194Q226 176 224 139Q225 112 243 94Q261 76 288 75Q315 76 333 94Q351 112 352 139ZM171 88Q160 111 160 139Q160 167 171 190Q176 203 171 215Q166 227 154 232Q141 237 130 233Q118 228 112 216Q96 180 96 139Q96 98 112 62Q118 50 130 45Q142 41 154 46Q166 51 171 63Q176 75 171 88ZM464 62Q480 98 480 139Q480 180 464 216Q458 228 446 233Q434 237 422 232Q410 227 405 215Q400 203 405 190Q416 167 416 139Q416 111 405 88Q400 75 405 63Q410 51 422 46Q435 41 446 45Q458 50 464 62Z'],
'fa-tower-broadcast': [576, 'M80 55Q64 94 64 139Q64 184 80 223Q85 236 80 247Q75 259 63 265Q50 270 38 265Q26 259 21 247Q0 197 0 139Q0 81 21 31Q26 19 38 14Q50 9 63 13Q75 19 80 30Q85 42 80 55ZM555 31Q576 81 576 139Q576 197 555 247Q550 259 538 264Q526 269 513 265Q501 259 496 248Q491 236 496 223Q512 184 512 139Q512 94 496 55Q491 42 496 31Q501 19 513 13Q526 8 538 13Q550 19 555 31ZM352 139Q350 176 320 194V491Q320 505 311 514Q302 523 288 523Q274 523 265 514Q256 505 256 491V194Q226 176 224 139Q225 112 243 94Q261 76 288 75Q315 76 333 94Q351 112 352 139ZM171 88Q160 111 160 139Q160 167 171 190Q176 203 171 215Q166 227 154 232Q141 237 130 233Q118 228 112 216Q96 180 96 139Q96 98 112 62Q118 50 130 45Q142 41 154 46Q166 51 171 63Q176 75 171 88ZM464 62Q480 98 480 139Q480 180 464 216Q458 228 446 233Q434 237 422 232Q410 227 405 215Q400 203 405 190Q416 167 416 139Q416 111 405 88Q400 75 405 63Q410 51 422 46Q435 41 446 45Q458 50 464 62Z'],
- 'fa-user': [448, 'M224 267Q259 267 288 250Q317 233 335 203Q352 173 352 139Q352 105 335 75Q317 45 288 28Q259 11 224 11Q189 11 160 28Q131 45 113 75Q96 105 96 139Q96 173 113 203Q131 233 160 250Q189 267 224 267ZM178 315Q103 317 52 367Q2 418 0 493Q0 506 9 514Q17 523 30 523H418Q431 523 439 514Q448 506 448 493Q446 418 396 367Q345 317 270 315H178Z'],
'fa-user-secret': [448, 'M224 27Q215 26 209 21Q208 21 208 21Q201 13 176 11Q153 12 137 39Q120 65 110 100Q74 107 53 117Q32 127 32 139Q35 161 97 175Q96 181 96 187Q96 213 105 235H45Q33 236 32 248Q32 251 33 253L72 350Q39 375 20 412Q0 449 0 493Q0 506 9 514Q17 523 30 523H418Q431 523 439 514Q448 506 448 493Q448 449 428 412Q409 375 376 350L415 253Q416 251 416 248Q415 236 403 235H343Q352 213 352 187Q352 181 351 175Q413 161 416 139Q416 127 395 117Q374 107 338 100Q328 65 311 39Q295 12 272 11Q247 13 240 21Q240 21 240 21Q239 21 239 21Q233 26 224 27ZM280 235H268H280H268Q241 234 231 209Q229 204 224 204Q219 204 217 209Q207 234 181 235H168Q151 235 140 223Q128 212 128 195V181Q171 187 224 187Q277 187 320 181V195Q320 212 308 223Q297 235 280 235ZM192 331 208 363 192 331 208 363 176 491 128 299 192 331ZM320 299 272 491 320 299 272 491 240 363 256 331 320 299Z'],
'fa-user-secret': [448, 'M224 27Q215 26 209 21Q208 21 208 21Q201 13 176 11Q153 12 137 39Q120 65 110 100Q74 107 53 117Q32 127 32 139Q35 161 97 175Q96 181 96 187Q96 213 105 235H45Q33 236 32 248Q32 251 33 253L72 350Q39 375 20 412Q0 449 0 493Q0 506 9 514Q17 523 30 523H418Q431 523 439 514Q448 506 448 493Q448 449 428 412Q409 375 376 350L415 253Q416 251 416 248Q415 236 403 235H343Q352 213 352 187Q352 181 351 175Q413 161 416 139Q416 127 395 117Q374 107 338 100Q328 65 311 39Q295 12 272 11Q247 13 240 21Q240 21 240 21Q239 21 239 21Q233 26 224 27ZM280 235H268H280H268Q241 234 231 209Q229 204 224 204Q219 204 217 209Q207 234 181 235H168Q151 235 140 223Q128 212 128 195V181Q171 187 224 187Q277 187 320 181V195Q320 212 308 223Q297 235 280 235ZM192 331 208 363 192 331 208 363 176 491 128 299 192 331ZM320 299 272 491 320 299 272 491 240 363 256 331 320 299Z'],
'fa-wand-magic-sparkles': [576, 'M235 54 197 68 235 54 197 68Q192 70 192 75Q192 80 197 82L235 96L249 134Q251 139 256 139Q261 139 263 134L277 96L315 82Q320 80 320 75Q320 70 315 68L277 54L263 16Q261 11 256 11Q251 11 249 16L235 54ZM46 406Q32 421 32 440Q32 459 46 474L81 509Q95 523 115 523Q134 523 149 509L530 128Q544 113 544 94Q544 74 530 60L495 25Q481 11 461 11Q442 11 427 25L46 406ZM485 94 380 199 485 94 380 199 356 175 461 70 485 94ZM8 128Q0 131 0 139Q0 147 8 150L64 171L85 228Q88 235 96 235Q104 235 107 228L128 171L185 150Q192 147 192 139Q192 131 185 128L128 107L107 51Q104 43 96 43Q88 43 85 51L64 107L8 128ZM360 384Q352 387 352 395Q352 403 360 406L416 427L437 484Q440 491 448 491Q456 491 459 484L480 427L537 406Q544 403 544 395Q544 387 537 384L480 363L459 307Q456 299 448 299Q440 299 437 307L416 363L360 384Z'],
'fa-wand-magic-sparkles': [576, 'M235 54 197 68 235 54 197 68Q192 70 192 75Q192 80 197 82L235 96L249 134Q251 139 256 139Q261 139 263 134L277 96L315 82Q320 80 320 75Q320 70 315 68L277 54L263 16Q261 11 256 11Q251 11 249 16L235 54ZM46 406Q32 421 32 440Q32 459 46 474L81 509Q95 523 115 523Q134 523 149 509L530 128Q544 113 544 94Q544 74 530 60L495 25Q481 11 461 11Q442 11 427 25L46 406ZM485 94 380 199 485 94 380 199 356 175 461 70 485 94ZM8 128Q0 131 0 139Q0 147 8 150L64 171L85 228Q88 235 96 235Q104 235 107 228L128 171L185 150Q192 147 192 139Q192 131 185 128L128 107L107 51Q104 43 96 43Q88 43 85 51L64 107L8 128ZM360 384Q352 387 352 395Q352 403 360 406L416 427L437 484Q440 491 448 491Q456 491 459 484L480 427L537 406Q544 403 544 395Q544 387 537 384L480 363L459 307Q456 299 448 299Q440 299 437 307L416 363L360 384Z'],
+ 'fa-gear': [512, 'M496 178Q500 192 490 202L446 242Q448 254 448 267Q448 280 446 292L490 332Q500 342 496 356Q489 374 480 391L475 399Q465 415 453 430Q443 441 429 437L373 419Q353 435 329 444L317 502Q313 516 298 519Q278 523 256 523Q234 523 213 519Q199 516 195 502L183 444Q159 435 139 419L83 437Q69 441 59 430Q46 415 37 399L32 391Q23 374 16 357Q12 342 22 332L66 293Q64 280 64 267Q64 254 66 242L22 202Q12 192 16 178Q23 160 32 143L37 135Q46 119 59 104Q69 93 83 97L139 115Q159 99 183 89L195 32Q199 18 214 15Q234 11 256 11Q278 11 299 15Q313 18 317 32L329 89Q353 99 373 115L429 97Q443 93 453 104Q466 119 476 135L480 143Q489 160 496 178ZM256 347Q301 346 325 307Q347 267 325 227Q301 188 256 187Q211 188 187 227Q165 267 187 307Q211 346 256 347Z'],
'fa-circle-half-stroke': [512, 'M448 267Q446 185 392 131Q338 77 256 75V459Q338 457 392 403Q446 349 448 267ZM0 267Q1 197 34 139Q68 81 128 45Q189 11 256 11Q323 11 384 45Q444 81 478 139Q511 197 512 267Q511 337 478 395Q444 453 384 489Q323 523 256 523Q189 523 128 489Q68 453 34 395Q1 337 0 267Z'],
'fa-circle-half-stroke': [512, 'M448 267Q446 185 392 131Q338 77 256 75V459Q338 457 392 403Q446 349 448 267ZM0 267Q1 197 34 139Q68 81 128 45Q189 11 256 11Q323 11 384 45Q444 81 478 139Q511 197 512 267Q511 337 478 395Q444 453 384 489Q323 523 256 523Q189 523 128 489Q68 453 34 395Q1 337 0 267Z'],
'fa-moon': [384, 'M224 43Q161 44 111 74Q60 103 30 154Q1 204 0 267Q1 330 31 380Q60 431 111 460Q161 490 224 491Q317 489 379 428Q387 419 382 409Q377 399 365 400Q351 403 335 403Q261 401 211 351Q162 302 160 227Q160 177 184 137Q209 97 249 74Q259 68 257 56Q254 46 242 44Q233 43 223 43Z'],
'fa-moon': [384, 'M224 43Q161 44 111 74Q60 103 30 154Q1 204 0 267Q1 330 31 380Q60 431 111 460Q161 490 224 491Q317 489 379 428Q387 419 382 409Q377 399 365 400Q351 403 335 403Q261 401 211 351Q162 302 160 227Q160 177 184 137Q209 97 249 74Q259 68 257 56Q254 46 242 44Q233 43 223 43Z'],
'fa-sun': [512, 'M362 12Q369 16 371 24L391 132L499 152Q507 154 511 161Q514 169 509 177L447 267L509 357Q514 365 511 373Q507 380 499 382L391 402L371 510Q369 518 362 522Q354 525 346 520L256 458L166 520Q158 525 151 522Q143 518 141 510L121 402L13 382Q5 380 1 373Q-2 365 3 357L65 267L3 177Q-2 169 1 162Q5 154 13 152L121 132L141 24Q143 16 151 12Q158 9 166 14L256 76L346 14Q354 9 362 12ZM160 267Q160 241 173 219Q186 197 208 184Q231 171 256 171Q281 171 304 184Q326 197 339 219Q352 241 352 267Q352 293 339 315Q326 337 304 350Q281 363 256 363Q231 363 208 350Q186 337 173 315Q160 293 160 267ZM384 267Q384 232 367 203Q350 174 320 156Q290 139 256 139Q222 139 192 156Q162 174 145 203Q128 232 128 267Q128 302 145 331Q162 360 192 378Q222 395 256 395Q290 395 320 378Q350 360 367 331Q384 302 384 267Z'],
'fa-sun': [512, 'M362 12Q369 16 371 24L391 132L499 152Q507 154 511 161Q514 169 509 177L447 267L509 357Q514 365 511 373Q507 380 499 382L391 402L371 510Q369 518 362 522Q354 525 346 520L256 458L166 520Q158 525 151 522Q143 518 141 510L121 402L13 382Q5 380 1 373Q-2 365 3 357L65 267L3 177Q-2 169 1 162Q5 154 13 152L121 132L141 24Q143 16 151 12Q158 9 166 14L256 76L346 14Q354 9 362 12ZM160 267Q160 241 173 219Q186 197 208 184Q231 171 256 171Q281 171 304 184Q326 197 339 219Q352 241 352 267Q352 293 339 315Q326 337 304 350Q281 363 256 363Q231 363 208 350Q186 337 173 315Q160 293 160 267ZM384 267Q384 232 367 203Q350 174 320 156Q290 139 256 139Q222 139 192 156Q162 174 145 203Q128 232 128 267Q128 302 145 331Q162 360 192 378Q222 395 256 395Q290 395 320 378Q350 360 367 331Q384 302 384 267Z'],
@@ -390,10 +395,10 @@
@@ -390,10 +395,10 @@
const NAV_ICONS_LAZY = {
const NAV_ICONS_LAZY = {
320: 'fa-chevron-right',
320: 'fa-chevron-right',
384: 'fa-xmark fa-arrow-down fa-play fa-plug fa-file-lines fa-location-dot',
384: 'fa-xmark fa-arrow-down fa-play fa-plug fa-file-lines fa-location-dot',
- 448: 'fa-book fa-hand-fist fa-bars fa-arrow-right fa-check fa-tag fa-bolt fa-font fa-lock fa-utensils',
- 512: 'fa-camera fa-gauge-high fa-list-check fa-paste fa-scissors fa-screwdriver-wrench fa-wallet fa-arrow-up-right-from-square fa-chevron-down fa-magnifying-glass fa-gear fa-file-pdf fa-clock fa-envelope fa-heart fa-circle-info fa-triangle-exclamation fa-globe fa-toolbox fa-comment-dots fa-server fa-newspaper fa-chart-line fa-pen-nib fa-key fa-satellite-dish fa-microchip fa-circle-nodes fa-download fa-upload fa-image fa-music',
- 576: 'fa-house fa-video fa-star fa-tower-cell fa-diagram-project fa-money-bill-wave fa-crown fa-ticket fa-map',
- 640: 'fa-comments fa-gamepad fa-network-wired fa-people-arrows fa-people-group fa-shirt fa-code fa-robot fa-photo-film fa-wave-square fa-user-shield',
+ 448: 'fa-book fa-hand-fist fa-user fa-bars fa-arrow-right fa-check fa-tag fa-bolt fa-font fa-lock fa-utensils',
+ 512: 'fa-camera fa-gauge-high fa-list-check fa-paste fa-scissors fa-screwdriver-wrench fa-wallet fa-arrow-up-right-from-square fa-chevron-down fa-magnifying-glass fa-file-pdf fa-clock fa-envelope fa-heart fa-circle-info fa-triangle-exclamation fa-globe fa-toolbox fa-comment-dots fa-server fa-newspaper fa-chart-line fa-pen-nib fa-key fa-satellite-dish fa-microchip fa-circle-nodes fa-download fa-upload fa-image fa-music',
+ 576: 'fa-house fa-id-card fa-video fa-star fa-tower-cell fa-diagram-project fa-money-bill-wave fa-crown fa-ticket fa-map',
+ 640: 'fa-comments fa-gamepad fa-link fa-network-wired fa-people-arrows fa-shirt fa-code fa-robot fa-photo-film fa-wave-square fa-user-shield',
};
};
const NAV_ICONS_REV = 'bb866b6e2cf3'; // sha256(nav-icons.js), first 12 hex: its ?v= (cacheable forever)
const NAV_ICONS_REV = 'bb866b6e2cf3'; // sha256(nav-icons.js), first 12 hex: its ?v= (cacheable forever)
// END generated
// END generated
@@ -891,14 +896,6 @@
@@ -891,14 +896,6 @@
}
}
/** Sites in the user menu: most used first (Frame data), never the one we are on. */
/** Sites in the user menu: most used first (Frame data), never the one we are on. */
- function acrossHTML() {
- const frame = OVFrame.get();
- const here = currentHost().toLowerCase();
- const list = (frame && frame.nav.length ? frame.nav.map(n => ({ name: n.name, url: n.url, icon: n.icon || n.id })) : LAUNCHER_SITES)
- .filter(n => { try { const h = new URL(n.url).hostname; return h !== here && !here.endsWith('.' + h); } catch { return false; } }).slice(0, 5);
- return list.map(n => `<a href="${escapeAttr(n.url)}"><span class="icon"><span class="ov-icon" data-icon="${escapeAttr(n.icon)}" data-size="20" data-fx="none"></span></span> ${escapeAttr(n.name)}</a>`).join('');
- }
-
/** Light / Dark / Auto: the theme's other half, or the device's (theme-loader.js scheme). */
/** Light / Dark / Auto: the theme's other half, or the device's (theme-loader.js scheme). */
function bindScheme(scope) {
function bindScheme(scope) {
const L = root.OpenVibeThemeLoader, box = scope.querySelector('.ud-scheme');
const L = root.OpenVibeThemeLoader, box = scope.querySelector('.ud-scheme');
@@ -923,7 +920,9 @@
@@ -923,7 +920,9 @@
/** OpenCoins (Network) and Vibes (OpenVibe.Billing) in the menu header: one request each when the menu first opens. */
/** OpenCoins (Network) and Vibes (OpenVibe.Billing) in the menu header: one request each when the menu first opens. */
let _walletLoaded = false;
let _walletLoaded = false;
async function loadWallet(dropdown) {
async function loadWallet(dropdown) {
- if (_walletLoaded || !_config.token || (_config.menu && _config.menu.headerChips)) return; _walletLoaded = true;
+ // The bar's chips (a site's own, or wallet: true) show the balances already: the menu does not ask twice.
+ const inBar = !!_config.wallet || (Array.isArray(_config.chips) && _config.chips.some(c => c && (c.id === 'coins' || c.id === 'vibes')));
+ if (_walletLoaded || !_config.token || inBar || (_config.menu && _config.menu.headerChips)) return; _walletLoaded = true;
const auth = { Authorization: `Bearer ${_config.token}` };
const auth = { Authorization: `Bearer ${_config.token}` };
const chip = (id, html) => { const el = dropdown.querySelector(id); if (el) { el.innerHTML = html; el.hidden = false; } };
const chip = (id, html) => { const el = dropdown.querySelector(id); if (el) { el.innerHTML = html; el.hidden = false; } };
const coins = fetch(`${_config.apiBase}/api/coins/me`, { headers: auth, credentials: 'include' }).then(async (r) => {
const coins = fetch(`${_config.apiBase}/api/coins/me`, { headers: auth, credentials: 'include' }).then(async (r) => {
@@ -1680,6 +1679,9 @@
@@ -1680,6 +1679,9 @@
const menuCfg = _config.menu || {};
const menuCfg = _config.menu || {};
const before = ((_config.menu && _config.menu.before) || []).concat(_runtimeMenu.before);
const before = ((_config.menu && _config.menu.before) || []).concat(_runtimeMenu.before);
const after = ((_config.menu && _config.menu.after) || []).concat(_runtimeMenu.after);
const after = ((_config.menu && _config.menu.after) || []).concat(_runtimeMenu.after);
+ // The bar shows the balances (a site's chips, or wallet: true): the menu does not repeat them.
+ const barWallet = !!_config.wallet || (Array.isArray(_config.chips) && _config.chips.some(c => c && (c.id === 'coins' || c.id === 'vibes')));
+ const admin = u.role === 'admin' || !!(u.capabilities && (u.capabilities.is_owner || u.capabilities.admin_panel));
dropdown.innerHTML = `
dropdown.innerHTML = `
<div class="openvibe-navbar-dropdown-header">
<div class="openvibe-navbar-dropdown-header">
@@ -1687,7 +1689,7 @@
@@ -1687,7 +1689,7 @@
<div class="info">
<div class="info">
<a class="name ud-me" href="${escapeAttr(meHref)}" title="${isAnon ? 'Your account' : 'Your profile'}">${escapeHtml(u.display_name || u.username)}</a>
<a class="name ud-me" href="${escapeAttr(meHref)}" title="${isAnon ? 'Your account' : 'Your profile'}">${escapeHtml(u.display_name || u.username)}</a>
<div class="email">${isAnon ? '' : '@' + escapeHtml(u.username || '')}</div>
<div class="email">${isAnon ? '' : '@' + escapeHtml(u.username || '')}</div>
- ${menuCfg.headerChips ? `<div class="ud-chips">${chipsHTML(menuCfg.headerChips, 'ovnav-chip ovnav-chip--menu')}</div>` : '<div class="ud-wallet" id="openvibe-wallet" hidden></div><div class="ud-wallet ud-vibes" id="openvibe-vibes" hidden></div>'}
+ ${barWallet ? '' : menuCfg.headerChips ? `<div class="ud-chips">${chipsHTML(menuCfg.headerChips, 'ovnav-chip ovnav-chip--menu')}</div>` : '<div class="ud-wallet" id="openvibe-wallet" hidden></div><div class="ud-wallet ud-vibes" id="openvibe-vibes" hidden></div>'}
${isAnon ? `<div class="anon-tag">Anonymous #${u.anon_number || '?'}</div>` : ''}
${isAnon ? `<div class="anon-tag">Anonymous #${u.anon_number || '?'}</div>` : ''}
</div>
</div>
</div>
</div>
@@ -1710,27 +1712,20 @@
@@ -1710,27 +1712,20 @@
<div class="openvibe-navbar-dropdown-menu">
<div class="openvibe-navbar-dropdown-menu">
${before.length ? `<div class="ud-label">${escapeAttr((_config.menu && _config.menu.label) || brand.short || 'This site')}</div>${before.map(menuItemHTML).join('')}<div class="sep"></div>` : ''}
${before.length ? `<div class="ud-label">${escapeAttr((_config.menu && _config.menu.label) || brand.short || 'This site')}</div>${before.map(menuItemHTML).join('')}<div class="sep"></div>` : ''}
${sectionsHTML(menuCfg.sections)}
${sectionsHTML(menuCfg.sections)}
+ ${after.length ? `${after.map(menuItemHTML).join('')}<div class="sep"></div>` : ''}
${menuCfg.defaults === false ? '' : `<div class="ud-label">You</div>
${menuCfg.defaults === false ? '' : `<div class="ud-label">You</div>
- <a href="https://openvibe.network/my"><span class="icon">${navIcon('fa-user')}</span> My Account</a>
- ${!isAnon && u.username ? `<a href="https://openvibe.network/@${escapeAttr(u.username)}"><span class="icon">${navIcon('fa-id-card')}</span> My Profile</a>` : ''}
- ${!isAnon && u.username ? `<a href="https://openvibe.live/@${escapeAttr(u.username)}"><span class="icon">${navIcon('fa-tower-broadcast')}</span> My Channel</a>` : ''}
+ <a href="https://openvibe.network/my"><span class="icon">${navIcon('fa-gear')}</span> Account & settings</a>
<a href="https://openvibe.network/my#notifications"><span class="icon">${navIcon('fa-bell')}</span> Notifications</a>
<a href="https://openvibe.network/my#notifications"><span class="icon">${navIcon('fa-bell')}</span> Notifications</a>
- ${!isAnon ? `<a href="https://openvibe.chat/vibe" data-ov-ask><span class="icon">${navIcon('fa-brain')}</span> Ask Vibe</a><a href="https://openvibe.chat/work" data-ov-work><span class="icon">${navIcon('fa-plus')}</span> Work together</a>` : ''}
+ ${!isAnon && u.username ? `<a href="https://openvibe.live/@${escapeAttr(u.username)}"><span class="icon">${navIcon('fa-tower-broadcast')}</span> My channel</a>` : ''}
+ <a href="https://openvibe.network/my#history"><span class="icon">${navIcon('fa-clock-rotate-left')}</span> History</a>
+ ${!isAnon ? `<a href="https://openvibe.chat/vibe" data-ov-ask><span class="icon">${navIcon('fa-brain')}</span> Ask Vibe</a><a href="https://openvibe.chat/work" data-ov-work><span class="icon">${navIcon('fa-people-group')}</span> Work together</a>` : ''}
+ ${admin ? `<a href="https://openvibe.network/admin"><span class="icon">${navIcon('fa-shield-halved')}</span> Admin</a>` : ''}
<div class="sep"></div>`}
<div class="sep"></div>`}
<div class="ud-label">Display</div>
<div class="ud-label">Display</div>
<div class="ud-scheme" role="group" aria-label="Light or dark" hidden><button type="button" data-ov-scheme="light" aria-pressed="false"><span class="icon">${navIcon('fa-sun')}</span> Light</button><button type="button" data-ov-scheme="dark" aria-pressed="false"><span class="icon">${navIcon('fa-moon')}</span> Dark</button><button type="button" data-ov-scheme="auto" aria-pressed="false" title="Follow this device's light or dark setting"><span class="icon">${navIcon('fa-circle-half-stroke')}</span> Auto</button></div>
<div class="ud-scheme" role="group" aria-label="Light or dark" hidden><button type="button" data-ov-scheme="light" aria-pressed="false"><span class="icon">${navIcon('fa-sun')}</span> Light</button><button type="button" data-ov-scheme="dark" aria-pressed="false"><span class="icon">${navIcon('fa-moon')}</span> Dark</button><button type="button" data-ov-scheme="auto" aria-pressed="false" title="Follow this device's light or dark setting"><span class="icon">${navIcon('fa-circle-half-stroke')}</span> Auto</button></div>
<button type="button" data-ov-display="text"><span class="icon">${navIcon('fa-text-height')}</span> Text size <b class="ud-val"></b></button>
<button type="button" data-ov-display="text"><span class="icon">${navIcon('fa-text-height')}</span> Text size <b class="ud-val"></b></button>
<button type="button" data-ov-display="motion"><span class="icon">${navIcon('fa-wand-magic-sparkles')}</span> Animations <b class="ud-val"></b></button>
<button type="button" data-ov-display="motion"><span class="icon">${navIcon('fa-wand-magic-sparkles')}</span> Animations <b class="ud-val"></b></button>
- <button type="button" data-ov-display="seasonal"><span class="icon">${navIcon('fa-palette')}</span> Seasonal themes <b class="ud-val"></b></button>
- <a href="https://openvibe.network/themes"><span class="icon">${navIcon('fa-palette')}</span> Themes</a>
- <div class="sep"></div>
- <div class="ud-label">Across OpenVibe</div>
- ${acrossHTML()}
- ${menuCfg.defaults === false ? '' : `
- <a href="https://openvibe.network/my#history"><span class="icon">${navIcon('fa-clock-rotate-left')}</span> History</a>
- <a href="https://openvibe.network/my#linked"><span class="icon">${navIcon('fa-link')}</span> Linked Services</a>
- ${u.role === 'admin' ? `<a href="https://openvibe.network/admin"><span class="icon">${navIcon('fa-shield-halved')}</span> Admin Panel</a>` : ''}`}
- ${after.length ? '<div class="sep"></div>' : ''}${after.map(menuItemHTML).join('')}
+ <a href="https://openvibe.network/themes" title="Every theme, and the season's own"><span class="icon">${navIcon('fa-palette')}</span> Themes <b class="ud-val ud-go" aria-hidden="true">›</b></a>
<div class="sep"></div>
<div class="sep"></div>
<button id="openvibe-logout-btn" class="danger"><span class="icon">${navIcon('fa-right-from-bracket')}</span> Sign Out</button>
<button id="openvibe-logout-btn" class="danger"><span class="icon">${navIcon('fa-right-from-bracket')}</span> Sign Out</button>
</div>
</div>
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-shared",
"name": "openvibe-shared",
- "version": "4.17.0",
+ "version": "4.18.0",
"description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site",
"description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site",
"main": "index.js",
"main": "index.js",
"bin": {
"bin": {
@@ -230,7 +230,13 @@ function load(hostname, opts = {}) {
@@ -230,7 +230,13 @@ function load(hostname, opts = {}) {
const dd = created.find(e => e.tag === 'div' && /openvibe-navbar-dropdown-menu/.test(e.innerHTML));
const dd = created.find(e => e.tag === 'div' && /openvibe-navbar-dropdown-menu/.test(e.innerHTML));
assert.ok(dd && dd.innerHTML.includes('data-menu-id="mp"') && dd.innerHTML.includes('My pastes'), 'custom dropdown row rendered');
assert.ok(dd && dd.innerHTML.includes('data-menu-id="mp"') && dd.innerHTML.includes('My pastes'), 'custom dropdown row rendered');
assert.ok(dd.innerHTML.includes('/my#history'), 'History link present');
assert.ok(dd.innerHTML.includes('/my#history'), 'History link present');
- assert.ok(dd.innerHTML.includes('href="https://openvibe.network/@x"') && dd.innerHTML.includes('My Profile'), 'the public profile (openvibe.network/@username) is one tap from the account menu');
+ assert.ok(dd.innerHTML.includes('href="https://openvibe.network/@x"') && !dd.innerHTML.includes('My Profile'), 'the public profile (openvibe.network/@username) is one tap away: the name and picture, not a row that repeats them');
+ // The account menu, reviewed (the owner, 2026-10-28: "duplicated things … so many icons sizes that aren't consistent"):
+ // no row says what another says, the seasonal switch is on the Themes page, and every icon sits in one box.
+ ['Seasonal themes', 'Linked Services', 'Switch account'].forEach((gone) => assert.ok(!dd.innerHTML.includes(gone), `no "${gone}" row`));
+ assert.ok(dd.innerHTML.includes('Account & settings') && dd.innerHTML.includes(' Themes <b class="ud-val ud-go"'), 'one row for the account, one for the themes');
+ assert.ok(!dd.innerHTML.includes('Across OpenVibe'), 'the other sites are the launcher\'s and the drawer\'s, not the account menu\'s');
+ assert.ok(/\.openvibe-navbar-dropdown-menu \.icon \.ovnav-ic \{ width: 1\.25em !important; height: 1em; \}/.test(require('fs').readFileSync(require('path').join(__dirname, '..', 'navbar.js'), 'utf8')), 'every menu icon in one fixed-width box');
assert.ok(dd.innerHTML.includes('<a class="name ud-me" href="https://openvibe.network/@x"'), 'pressing your name in the menu opens your profile');
assert.ok(dd.innerHTML.includes('<a class="name ud-me" href="https://openvibe.network/@x"'), 'pressing your name in the menu opens your profile');
assert.ok(['light', 'dark', 'auto'].every((m) => dd.innerHTML.includes(`data-ov-scheme="${m}"`)) && dd.innerHTML.includes('aria-label="Light or dark"'), 'Light, Dark and Auto are one press away in the account menu');
assert.ok(['light', 'dark', 'auto'].every((m) => dd.innerHTML.includes(`data-ov-scheme="${m}"`)) && dd.innerHTML.includes('aria-label="Light or dark"'), 'Light, Dark and Auto are one press away in the account menu');
assert.ok(dd.innerHTML.includes('<a class="ud-me" href="https://openvibe.network/@x" tabindex="-1" aria-hidden="true"><img'), 'and so does your picture (one stop for keyboards)');
assert.ok(dd.innerHTML.includes('<a class="ud-me" href="https://openvibe.network/@x" tabindex="-1" aria-hidden="true"><img'), 'and so does your picture (one stop for keyboards)');
@@ -48,10 +48,15 @@ function dropdown() {
@@ -48,10 +48,15 @@ function dropdown() {
assert.strictEqual(d.els['#openvibe-wallet'].hidden, false);
assert.strictEqual(d.els['#openvibe-wallet'].hidden, false);
assert.strictEqual(d.els['#openvibe-vibes'].hidden, true, 'no shadow balance');
assert.strictEqual(d.els['#openvibe-vibes'].hidden, true, 'no shadow balance');
- // A site with its own header chips (Live) and a signed-out page ask nothing.
+ // A site with its own header chips (Live), a bar that shows the balances already, and a signed-out page ask nothing.
calls.length = 0;
calls.length = 0;
configure({ token: 'tok', menu: { headerChips: [] } });
configure({ token: 'tok', menu: { headerChips: [] } });
await loadWallet(dropdown());
await loadWallet(dropdown());
+ configure({ token: 'tok', menu: null, wallet: true });
+ await loadWallet(dropdown());
+ configure({ token: 'tok', menu: null, wallet: false, chips: [{ id: 'coins', value: '1' }] });
+ await loadWallet(dropdown());
+ configure({ chips: [] });
configure({ token: null, menu: null });
configure({ token: null, menu: null });
await loadWallet(dropdown());
await loadWallet(dropdown());
assert.strictEqual(calls.length, 0);
assert.strictEqual(calls.length, 0);