fix: cerrar la integracion 0.9.5 — recursos que faltaban y regresiones

Una revision a fondo del arbol contra 0.9.5 saco varios fallos, unos heredados y
otros que introdujo la propia integracion. Verificados uno a uno antes de tocar.

Recursos referenciados que no existian (los introduje al adoptar vistas de 0.9.5
que los usan, mientras la rama los habia borrado):
- Los cuatro temas *-SNH.css. settings_view ofrece Dark, Clear, Matrix y Purple,
  pero solo estaba OasisMobile: elegir cualquiera daba 404 y la app se quedaba sin
  estilos. Ahora los cuatro responden 200.
- pdf.min.mjs, pdf.worker.min.mjs y pdf-viewer.js, referenciados desde seis vistas.

Regresiones revertidas a 0.9.5 verbatim en catorce ficheros. Las de fondo:
- larp_model perdio getGoverningPeriodId, que backend.js llama: el anuncio de
  gobierno no salia nunca, con el TypeError tragado por un catch.
- courts_view y search_view tenian selected: false, que hyperscript SI serializa
  como atributo y HTML interpreta como seleccionado. La forma de upstream, el
  spread condicional, es la correcta.
- pm_model perdio includeDeleted, projects_model la validacion de deadline pasado,
  jobs_model el desempate por timestamp, middleware el flag de debug HTTP.

forum_view pasa a 0.9.5 conservando el filtro hot. Esto arregla un fallo activo: la
vista de la rama declaraba un cuarto parametro topic y backend.js llama con cinco
argumentos, asi que al abrir una respuesta el %clave del hilo se colaba como tema y
el hilo salia VACIO. Upstream pasa los mismos cinco argumentos a una firma de tres y
JS los ignora, que es lo correcto.

chats_view pasa a 0.9.5 y se implementa replyTo de verdad. Estaba muerto de punta a
punta: backend.js no leia ctx.query.replyTo ni pasaba el cuarto argumento a
sendMessage, asi que ningun mensaje llegaba a tener replyTo y la cita no se
renderizaba jamas. Ahora la cadena esta completa —modelo, GET, POST y vista— con
indice msgById armado antes de mezclar con las encuestas, y sin gate de movil:
responder a un mensaje no es una funcion de movil.

aria-label: encontrada la causa. No es que hyperaxe lo ignore, es que hyperscript
solo asigna como propiedad y html-element solo serializa atributos de su tabla, en
la que aria-* no esta; data-* si tiene rama propia, por eso las tablas responsive
funcionaban. Se arregla con el escape hatch attrs:{}, sin tocar node_modules.

prepare.sh copia README.md y falla si no esta: backend.js lo lee con readFileSync
sin try/catch, de modo que sin el fichero el backend muere con ENOENT al arrancar.

Verificado con la app en marcha: 17 rutas OK, los cuatro recursos que faltaban
sirviendo 200, aria-label emitido en el HTML, e interfaz intacta (10 categorias,
50 modulos, 7 accesos rapidos, 0 etiquetas vacias).
This commit is contained in:
SITO 2026-08-18 23:48:14 +02:00
parent 7459644a73
commit c3a1c841e6
27 changed files with 1994 additions and 220 deletions

View file

@ -0,0 +1,372 @@
body {
background-color: #F9F9F9 !important;
color: #2C2C2C !important;
font-family: 'Roboto', sans-serif !important;
}
.main-column {
background-color: #FFFFFF !important;
border: 1px solid #E0E0E0 !important;
}
button, input[type="submit"], input[type="button"] {
background-color: #FF6F00 !important;
color: #FFFFFF !important;
border: none !important;
border-radius: 6px !important;
padding: 10px 20px !important;
cursor: pointer !important;
font-weight: 600 !important;
}
button:hover, input[type="submit"]:hover, input[type="button"]:hover {
background-color: #FF8F00 !important;
}
input, textarea, select {
background-color: #FFFFFF !important;
color: #2C2C2C !important;
border: 1px solid #E0E0E0 !important;
border-radius: 4px !important;
padding: 8px !important;
font-size: 16px !important;
}
a {
color: #007BFF !important;
text-decoration: none !important;
}
a:hover {
text-decoration: underline !important;
}
p {
color: black !important;
text-decoration: none !important;
}
.created-at, .about-time, .time {
font-size: 0.9rem;
color: black;
}
table {
background-color: #FFFFFF !important;
color: #2C2C2C !important;
width: 100% !important;
border-collapse: collapse !important;
}
table th {
background-color: #F8F8F8 !important;
padding: 12px 15px !important;
text-align: left !important;
font-weight: 600 !important;
}
table tr:nth-child(even) {
background-color: #FAFAFA !important;
}
table td {
padding: 12px 15px !important;
}
.profile {
background-color: #FFFFFF !important;
padding: 20px !important;
border-radius: 8px !important;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important;
}
.profile .name {
color: #FF6F00 !important;
font-size: 20px !important;
font-weight: 700 !important;
}
.avatar {
border: 3px solid #FF6F00 !important;
border-radius: 50% !important;
width: 60px !important;
height: 60px !important;
}
article, section {
background-color: #FFFFFF !important;
color: #2C2C2C !important;
padding: 20px !important;
border-radius: 8px !important;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05) !important;
}
.post-preview img {
border-radius: 8px !important;
max-width: 100% !important;
height: auto !important;
}
div {
background-color: #FFFFFF !important;
border: 1px solid #E0E0E0 !important;
}
::-webkit-scrollbar-thumb {
background-color: #B0B0B0 !important;
}
::-webkit-scrollbar-track {
background-color: #F9F9F9 !important;
}
.action-container {
background-color: #FFFFFF !important;
border-color: #E0E0E0 !important;
color: #2C2C2C !important;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05) !important;
}
footer {
background-color: #FFFFFF !important;
border-top: 1px solid #E0E0E0 !important;
padding: 15px 0 !important;
}
footer a {
background-color: #007BFF !important;
color: #FFFFFF !important;
padding: 10px 20px !important;
border-radius: 6px !important;
text-decoration: none !important;
font-weight: 600 !important;
}
footer a:hover {
background-color: #0056b3 !important;
}
.sidebar-left nav ul,
.sidebar-right nav ul {
display: flex !important;
flex-direction: column !important;
}
.sidebar-left nav ul,
.sidebar-right nav ul {
display: flex;
flex-direction: column;
margin: 0;
}
.sidebar-left nav ul li,
.sidebar-right nav ul li {
width: 100%;
display: block;
}
.sidebar-left nav ul li a,
.sidebar-right nav ul li a,
.header nav ul li a {
display: block;
width: 100%;
padding: 12px 16px;
font-size: 15px;
font-weight: 500;
border-radius: 6px;
background-color: #ffffff !important;
color: #2C2C2C !important;
border: 1px solid #D0D0D0 !important;
text-align: left;
box-sizing: border-box;
}
.sidebar-left nav ul li a:hover,
.sidebar-right nav ul li a:hover,
.header nav ul li a:hover {
background-color: #f0f0f0 !important;
}
.filter-btn,
.create-button,
.edit-btn,
.delete-btn,
.join-btn,
.leave-btn,
.buy-btn {
background-color: #FF6F00 !important;
color: #FFFFFF !important;
border: none !important;
}
.filter-btn:hover,
.create-button:hover {
background-color: #FF8F00 !important;
color: #FFFFFF !important;
}
.card {
color: #4A4A4A;
box-shadow: 0 4px 30px 0 rgba(0, 0, 0, 0.1);
background-color: #F4F4F4;
}
.card-label {
color: #2D2D2D;
}
.card-footer {
color: #6C6C6C;
background: none;
}
.card-field {
background: none;
}
.card-tags a.tag-link {
color: #181818;
background: #D94F4F;
}
.card-tags a.tag-link:hover {
background: #D94F4F;
color: #111;
cursor: pointer;
}
a.user-link {
background-color: #FFD600;
color: #FFFFFF;
border-color: #FFD600;
transition: background-color 0.3s, color 0.3s, border-color 0.3s;
}
a.user-link:hover {
background-color: #FFD600;
border-color: #FFD600;
color: #FFFFFF;
cursor: pointer;
}
a.user-link:focus {
background-color: #9A2F2F;
border-color: #9A2F2F;
color: #FFFFFF;
}
.date-link {
background-color: #2F3C32;
color: #fff;
}
.date-link:hover {
background-color: #3E4A3D;
color: #fff;
}
.activitySpreadInhabitant2 {
background-color: #3E4A3D;
color: #fff;
}
.activityVotePost {
background-color: #3B5C42;
color: #fff;
}
.update-banner {
background-color: #FFF3E0 !important;
border-bottom-color: #FFE0B2 !important;
color: #E65100 !important;
}
.update-banner-link {
color: #FF6F00 !important;
}
.snh-invite-code {
color: #007BFF !important;
}
.carbon-bar-track {
background: #e0e0e0 !important;
}
.carbon-bar-max {
background: #cc7700 !important;
}
.stats-kpi-label { color: #2D2D2D !important; }
.stats-kpi-value { color: #007BFF !important; }
.carbon-bar-note, .carbon-bar-formula { color: #007BFF !important; }
.graphos-node-label { fill: #2C2C2C !important; }
.graphos-node-label-me { fill: #cc7700 !important; }
.data-best-label { color: #cc7700 !important; }
.data-best-card { background: #FFF3E0 !important; border: 1px solid rgba(204, 119, 0, .4) !important; }
.graphos-legend { color: #2C2C2C !important; }
.graphos-edge { stroke: #BBB !important; }
.graphos-edge-discovered { stroke: #b8860b !important; }
.graphos-edge-unknown { stroke: #999 !important; }
.graphos-node-circle-discovered { fill: #ffd700 !important; stroke: #b8860b !important; }
.graphos-legend-dot.graphos-node-circle-discovered { background: #ffd700 !important; border-color: #b8860b !important; }
/* Blockexplorer */
.blockchain-view { background-color: #F4F4F4 !important; color: #2C2C2C !important; }
.block { background: #FFFFFF !important; box-shadow: 0 2px 12px rgba(0,0,0,0.06) !important; }
.block:hover { box-shadow: 0 8px 32px rgba(0,0,0,0.10) !important; }
.blockchain-card-label, .block-info-table .card-label, .pm-info-table .card-label, .block-content-label { color: #2D2D2D !important; }
.blockchain-card-value, .block-info-table .card-value, .pm-info-table .card-value, .block-timestamp, .json-content { color: #007BFF !important; }
.block-content-preview, .block-content { background: #F8F8F8 !important; color: #2C2C2C !important; }
.block-author { color: #FF6F00 !important; background: rgba(255,111,0,0.08) !important; }
.block-author:hover { color: #FF8F00 !important; }
.block-url { color: #007BFF !important; }
.block-row--details .block-url { background: #F0F0F0 !important; }
.block-row--details .block-url:hover { background: #E0E0E0 !important; color: #FF6F00 !important; }
.btn-singleview { background: #F0F0F0 !important; color: #FF6F00 !important; }
.btn-singleview:hover { background: #E0E0E0 !important; color: #FF8F00 !important; }
.btn-spread-on, .content-actions .btn-pin-on { background: #FF6F00 !important; color: #FFFFFF !important; }
.btn-spread-on:hover, .content-actions .btn-pin-on:hover { background: #FF8F00 !important; color: #FFFFFF !important; }
.btn-back { background: #FF6F00 !important; color: #FFFFFF !important; }
.btn-back:hover { background: #FF8F00 !important; color: #FFFFFF !important; }
.block-info-table td, .pm-info-table td { border-color: #E0E0E0 !important; }
.block-diagram { border-color: #E0E0E0 !important; background: #FFFFFF !important; }
.block-diagram-ruler { color: #2D2D2D !important; background: #F8F8F8 !important; border-bottom-color: #E0E0E0 !important; }
.block-diagram-ruler span { color: #2D2D2D !important; }
.block-diagram-cell { border-color: #E0E0E0 !important; background: #FFFFFF !important; }
.bd-label { color: #2D2D2D !important; }
.bd-value { color: #007BFF !important; }
.deleted-label { color: #D32F2F !important; }
/* Tribes */
.tribe-card { background: #FFFFFF !important; border-color: #E0E0E0 !important; }
.tribe-card:hover { border-color: #007BFF !important; }
.tribe-card-title { color: #2D2D2D !important; }
.tribe-card-description { color: #555 !important; }
.tribe-info-table td { border-color: #E0E0E0 !important; }
.tribe-info-label { color: #2D2D2D !important; background: #FFFFFF !important; }
.tribe-info-value { color: #007BFF !important; background: #FFFFFF !important; }
.tribe-info-empty { color: #999 !important; }
.tribe-card-members { border-color: #E0E0E0 !important; background: #F8F8F8 !important; }
.tribe-members-count { color: #FF6F00 !important; }
.tribe-card-actions { border-color: #E0E0E0 !important; background: #F8F8F8 !important; }
.tribe-action-btn { border-color: #FF6F00 !important; color: #FF6F00 !important; }
.tribe-action-btn:hover { background: #FF6F00 !important; color: #fff !important; }
.tribe-subtribe-link { background: #F0F0F0 !important; border-color: #E0E0E0 !important; color: #FF6F00 !important; }
.tribe-thumb-link { border-color: #E0E0E0 !important; }
.tribe-thumb-link:hover { border-color: #FF6F00 !important; }
.tribe-subtribe-link:hover { background: #E0E0E0 !important; }
.tribe-parent-image { border-color: #E0E0E0 !important; }
.tribe-parent-box { background: #FFFFFF !important; }
.chat-message { background: #FFFFFF !important; border: 1px solid #E0E0E0 !important; }
.chat-bubble-row-self .chat-message { background: #FFF3E0 !important; border-color: rgba(204, 119, 0, .35) !important; }
.chat-message-author { background: #FDF6EC !important; }
.chat-bubble-sender { color: #1565C0 !important; }
.chat-bubble-sender-owner { color: #cc7700 !important; }
.chat-bubble-time { color: #999 !important; }
.chat-day-chip { background: #F0F0F0 !important; color: #666 !important; border-color: #DDD !important; }
.chat-topics { background: #FAFAFA !important; border-color: #E0E0E0 !important; }
.chat-topic:hover { background: #F0F0F0 !important; }
.chat-topic-active { background: #FFF3E0 !important; }
.chat-topic-title { color: #2D2D2D !important; }
.chat-workspace-empty { border-color: #DDD !important; }

View file

@ -0,0 +1,364 @@
body {
background-color: #121212;
color: #FFD700;
}
header, footer {
background-color: #1F1F1F;
}
.sidebar-left, .sidebar-right {
background-color: #1A1A1A;
border: 1px solid #333;
}
.main-column {
background-color: #1C1C1C;
}
button, input[type="submit"], input[type="button"] {
background-color: #444;
color: #FFD700;
border: 1px solid #444;
}
button:hover, input[type="submit"]:hover, input[type="button"]:hover {
background-color: #333;
border-color: #666;
}
input, textarea, select {
background-color: #333;
color: #FFD700;
border: 1px solid #555;
}
a {
color: #FFD700;
}
a:hover {
color: #FFDD44;
}
table {
background-color: #222;
color: #FFD700;
}
table th {
background-color: #333;
}
table tr:nth-child(even) {
background-color: #2A2A2A;
}
nav ul li a:hover {
color: #FFDD44;
text-decoration: underline;
}
.profile {
background-color: #222;
padding: 15px;
border-radius: 8px;
}
.profile .name {
color: #FFD700;
}
.avatar {
border: 3px solid #FFD700;
}
article, section {
background-color: #1C1C1C;
color: #FFD700;
}
.article img {
border: 3px solid #FFD700;
}
.post-preview img {
border: 3px solid #FFD700;
}
.post-preview .image-container {
max-width: 100%;
overflow: hidden;
display: block;
margin: 0 auto;
}
div {
background-color: #1A1A1A;
border: 1px solid #333;
}
div .header-content {
width: 100%;
}
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-thumb {
background-color: #444;
border-radius: 10px;
}
::-webkit-scrollbar-track {
background-color: #222;
}
.action-container {
background-color: #1A1A1A;
border: 1px solid #333;
padding: 10px;
border-radius: 8px;
color: #FFD700;
}
footer {
background-color: #1F1F1F;
padding: 10px 0;
}
footer a {
background-color: #444;
color: #FFD700;
text-align: center;
padding: 8px 16px;
border-radius: 5px;
text-decoration: none;
}
footer a:hover {
background-color: #333;
color: #FFDD44;
}
.card {
border-radius: 16px;
padding: 0px 24px 10px 24px;
margin-bottom: 16px;
color: #FFD600;
font-family: inherit;
box-shadow: 0 2px 20px 0 #FFD60024;
}
.card-section {
border:none;
padding: 10px 0 0 16px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 0px;
margin-top: 8px;
padding-top: 0px;
border: none;
}
.card-label {
color: #ffa300;
font-weight: bold;
letter-spacing: 1.5px;
line-height: 1.2;
margin-bottom: 0;
}
.card-footer {
margin-top: 6px;
font-weight: 500;
color: #ff9900;
font-size: 1.07em;
display: flex;
align-items: center;
gap: 8px;
background: none;
border: none;
padding-top: 0;
margin-bottom: 6;
}
.card-body {
margin-top: 0;
margin-bottom: 4;
padding: 0;
}
.card-field {
display: flex;
align-items: baseline;
padding: 0;
margin-bottom: 0;
border: none;
background: none;
}
.card-tags {
margin: 5px 0 3px 0;
display: flex;
flex-wrap: wrap;
gap: 9px;
}
.card-tags a.tag-link {
text-decoration: none;
color: #181818;
background: #FFD600;
padding: 5px 13px 4px 13px;
border-radius: 7px;
font-size: .98em;
border: none;
font-weight: bold;
}
.card-tags a.tag-link:hover {
background: #ffe86a;
color: #111;
cursor: pointer;
}
a.user-link {
background-color: #FFA500;
color: #000;
padding: 8px 16px;
border-radius: 5px;
text-align: center;
font-weight: bold;
text-decoration: none;
display: inline-block;
border: 2px solid transparent;
transition: background-color 0.3s, color 0.3s, border-color 0.3s;
font-size: 0.8em;
}
a.user-link:hover {
background-color: #FFD700;
border-color: #FFD700;
color: #000;
cursor: pointer;
}
a.user-link:focus {
background-color: #007B9F;
border-color: #007B9F;
color: #fff;
}
.date-link {
background-color: #444;
color: #FFD600;
padding: 8px 16px;
border-radius: 5px;
margin-left: 8px;
}
.date-link:hover {
background-color: #555;
color: #FFD700;
}
.activitySpreadInhabitant2 {
background-color: #007B9F;
color: #fff;
padding: 8px 16px;
border-radius: 5px;
font-weight: bold;
text-decoration: none;
display: inline-block;
border: 2px solid transparent;
}
.activityVotePost {
background-color: #557d3b;
color: #fff;
padding: 8px 16px;
border-radius: 5px;
font-weight: bold;
text-decoration: none;
display: inline-block;
border: 2px solid transparent;
}
.update-banner {
background-color: #1a1400;
border-bottom-color: #3a2e00;
color: #FFD700;
}
.update-banner-link {
color: #FFD700;
}
.oasis-footer-center a {
color: #FFA500;
}
.oasis-footer-center a:hover {
color: #FFD700;
}
.snh-invite-code {
color: #FFA500 !important;
}
/* Blockexplorer */
.stats-kpi-label { color: #ffa300 !important; }
.stats-kpi-value { color: #FFD700 !important; }
.carbon-bar-note, .carbon-bar-formula { color: #FFD700 !important; }
.graphos-node-label { fill: #ddd !important; }
.graphos-node-label-me { fill: #ffa500 !important; }
.graphos-legend { color: #ddd !important; }
.blockchain-view { background-color: #191b20 !important; color: #FFD700 !important; }
.block { background: #23242a !important; }
.block:hover { box-shadow: 0 8px 32px rgba(35,40,50,0.18) !important; }
.blockchain-card-label, .block-info-table .card-label, .pm-info-table .card-label, .block-content-label { color: #ffa300 !important; }
.blockchain-card-value, .block-info-table .card-value, .pm-info-table .card-value, .block-timestamp, .json-content { color: #FFD700 !important; }
.block-content-preview, .block-content { background: #222326 !important; color: #FFD700 !important; }
.block-author { color: #FFD700 !important; background: rgba(255,163,0,0.08) !important; }
.block-author:hover { color: #FFDD44 !important; }
.block-url { color: #FFD700 !important; }
.block-row--details .block-url { background: #1f2023 !important; }
.block-row--details .block-url:hover { background: #292b36 !important; color: #ffa300 !important; }
.btn-singleview { background: #1e1f23 !important; color: #ffa300 !important; }
.btn-singleview:hover { background: #2d2e34 !important; color: #FFD700 !important; }
.btn-spread-on, .content-actions .btn-pin-on { background: #ffa300 !important; color: #000000 !important; }
.btn-spread-on:hover, .content-actions .btn-pin-on:hover { background: #ffb733 !important; color: #000000 !important; }
.btn-back { background: #21232b !important; color: #ffa300 !important; }
.btn-back:hover { background: #292b36 !important; color: #FFD700 !important; }
.block-info-table td, .pm-info-table td { border-color: #444 !important; }
.block-diagram { border-color: #555 !important; background: #191b20 !important; }
.block-diagram-ruler { color: #ffa300 !important; background: #111 !important; border-bottom-color: #555 !important; }
.block-diagram-ruler span { color: #ffa300 !important; }
.block-diagram-cell { border-color: #555 !important; background: #1e1f23 !important; }
.bd-label { color: #ffa300 !important; }
.bd-value { color: #FFD700 !important; }
/* Tribes */
.tribe-card { background: #23242a !important; border-color: #444 !important; }
.tribe-card:hover { border-color: #ffa300 !important; }
.tribe-card-description { color: #cfd3e1 !important; }
.tribe-info-table td { border-color: #444 !important; }
.tribe-info-label { color: #ffa300 !important; background: #1e1f23 !important; }
.tribe-info-value { color: #FFD700 !important; background: #1e1f23 !important; }
.tribe-info-empty { color: #9aa3b2 !important; }
.tribe-card-members { border-color: #444 !important; background: #1e1f23 !important; }
.tribe-members-count { color: #ffa300 !important; }
.tribe-card-actions { border-color: #444 !important; background: #1e1f23 !important; }
.tribe-action-btn { border-color: #ffa300 !important; color: #ffa300 !important; }
.tribe-action-btn:hover { background: #ffa300 !important; color: #000 !important; }
.tribe-subtribe-link { background: #191b20 !important; border-color: #444 !important; color: #ffa300 !important; }
.tribe-thumb-link { border-color: #444 !important; }
.tribe-thumb-link:hover { border-color: #ffa300 !important; }
.tribe-subtribe-link:hover { background: #333 !important; }
.tribe-parent-image { border-color: #ffa300 !important; }
.tribe-parent-box { background: #1e1f23 !important; }

View file

@ -0,0 +1,382 @@
body {
background-color: #000000 !important;
color: #00FF00 !important;
font-family: 'Courier New', monospace;
}
header, footer {
background-color: #000000;
color: #00FF00;
padding: 20px;
text-align: center;
font-size: 18px;
}
footer {
border-top: 2px solid #00FF00;
}
.sidebar-left, .sidebar-right {
background-color: #000000;
color: #00FF00;
border-right: 2px solid #00FF00;
padding: 15px;
margin-bottom: 10px;
}
.main-column {
background-color: #000000;
color: #00FF00;
padding: 20px;
border-left: 2px solid #00FF00;
margin-bottom: 20px;
}
button, input[type="submit"], input[type="button"] {
background-color: #000000;
color: #00FF00;
border: 2px solid #00FF00;
border-radius: 8px;
padding: 10px 20px;
cursor: pointer;
font-family: 'Courier New', monospace;
text-transform: none;
font-size: 16px;
}
button:hover, input[type="submit"]:hover, input[type="button"]:hover {
background-color: #00FF00;
color: #000000;
border-color: #00FF00;
box-shadow: 0 0 10px rgba(0, 255, 0, 0.8);
}
input, textarea, select {
background-color: #1A1A1A;
color: #00FF00;
border: 1px solid #00FF00;
border-radius: 5px;
padding: 10px;
font-family: 'Courier New', monospace;
font-size: 16px;
}
a {
color: #00FF00;
text-decoration: none;
font-weight: normal;
font-size: 16px;
}
table {
background-color: #000000;
color: #00FF00;
width: 100%;
border: 1px solid #00FF00;
font-size: 16px;
}
table th {
background-color: #00FF00;
color: #000000;
}
table tr:nth-child(even) {
background-color: #1A1A1A;
}
nav ul {
background-color: #000000;
padding: 0;
margin: 0;
}
nav ul li {
display: inline-block;
margin-right: 10px;
}
nav ul li a {
color: #00FF00;
padding: 10px;
display: inline-block;
font-family: 'Courier New', monospace;
text-transform: none;
font-size: 16px;
}
.profile {
background-color: #1A1A1A;
color: #00FF00;
padding: 20px;
border-radius: 8px;
border: 1px solid #00FF00;
box-shadow: 0 2px 5px rgba(0,255,0,0.5);
}
.profile .name {
color: #00FF00;
font-size: 18px;
font-weight: bold;
}
.avatar {
border: 4px solid #00FF00;
border-radius: 50%;
width: 80px;
height: 80px;
margin-bottom: 10px;
}
article, section {
background-color: #1A1A1A;
color: #00FF00;
padding: 20px;
border-radius: 10px;
border: 1px solid #00FF00;
box-shadow: 0 4px 10px rgba(0, 255, 0, 0.5);
}
.post-preview {
background-color: #00FF00;
padding: 15px;
border-radius: 8px;
color: #000000;
}
.post-preview img {
border-radius: 8px;
max-width: 100%;
}
::-webkit-scrollbar-thumb {
background-color: #00FF00;
}
::-webkit-scrollbar-track {
background-color: #000000;
}
.action-container {
background-color: #1A1A1A;
border-color: #00FF00;
color: #00FF00;
}
footer a {
background-color: #00FF00;
color: #000000;
padding: 8px 20px;
border-radius: 5px;
text-decoration: none;
}
.top-bar-left,
.top-bar-mid,
.top-bar-right {
background-color: #000000 !important;
border: 2px solid #00FF00 !important;
padding: 12px 16px;
box-shadow: 0 0 12px #00FF00;
border-radius: 8px;
display: flex;
gap: 12px;
}
.sidebar-left,
.sidebar-right {
background-color: #000000 !important;
border: 2px solid #00FF00 !important;
box-shadow: 0 0 15px #00FF00;
padding: 16px;
}
.sidebar-left nav ul,
.sidebar-right nav ul {
display: flex;
flex-direction: column;
gap: 10px;
margin: 0;
padding: 0;
}
.sidebar-left nav ul li,
.sidebar-right nav ul li {
width: 100%;
}
.sidebar-left nav ul li a,
.sidebar-right nav ul li a,
.header nav ul li a {
background-color: #000000 !important;
color: #00FF00 !important;
border: 1px solid #00FF00 !important;
font-weight: bold;
border-radius: 6px;
padding: 10px 14px;
display: flex;
justify-content: flex-start;
box-shadow: 0 0 6px #00FF00;
transition: background-color 0.3s ease, color 0.3s ease;
}
.sidebar-left nav ul li a:hover,
.sidebar-right nav ul li a:hover,
.header nav ul li a:hover {
background-color: #00FF00 !important;
color: #000000 !important;
}
.card {
color: #00FF00;
font-family: 'Courier New', monospace;
background-color: #1A1A1A;
}
.card-label {
color: #00FF00;
}
.card-footer {
color: #00FF00;
}
.card-tags a.tag-link {
color: #00FF00;
background: #000000;
}
.card-tags a.tag-link:hover {
background: #00FF00;
color: #000000;
cursor: pointer;
}
a.user-link {
background-color: #00FF00;
color: #000000;
border-color: #00FF00;
transition: background-color 0.3s, color 0.3s, border-color 0.3s;
}
a.user-link:hover {
background-color: #000000;
border-color: #00FF00;
color: #00FF00;
cursor: pointer;
}
a.user-link:focus {
background-color: #00FF00;
border-color: #00FF00;
color: #000000;
}
.date-link {
background-color: #00FF00;
color: #000000;
}
.date-link:hover {
background-color: #000000;
color: #00FF00;
}
.activitySpreadInhabitant2 {
background-color: #1A1A1A;
color: #00FF00;
}
.activityVotePost {
background-color: #00FF00;
color: #000000;
}
.update-banner {
background-color: #001a00;
border-bottom-color: #003300;
color: #00FF00;
}
.update-banner-link {
color: #00FF00;
}
.snh-invite-code {
color: #00FF00 !important;
}
.stats-kpi-label { color: #00FF00 !important; }
.stats-kpi-value { color: #00FF00 !important; }
.carbon-bar-note, .carbon-bar-formula { color: #00FF00 !important; }
.graphos-node-label { fill: #00FF00 !important; }
.graphos-node-label-me { fill: #ffa500 !important; font-weight: bold !important; }
.graphos-legend { color: #00FF00 !important; }
.graphos-edge { stroke: #003300 !important; }
/* Blockexplorer */
.blockchain-view { background-color: #000000 !important; color: #00FF00 !important; }
.block { background: #1A1A1A !important; border: 1px solid #00FF00 !important; }
.block:hover { box-shadow: 0 0 15px rgba(0,255,0,0.3) !important; }
.blockchain-card-label, .block-info-table .card-label, .pm-info-table .card-label, .block-content-label { color: #00FF00 !important; }
.blockchain-card-value, .block-info-table .card-value, .pm-info-table .card-value, .block-timestamp, .json-content { color: #00FF00 !important; }
.block-content-preview, .block-content { background: #1A1A1A !important; color: #00FF00 !important; }
.block-author { color: #00FF00 !important; background: rgba(0,255,0,0.08) !important; }
.block-author:hover { color: #00FF00 !important; }
.block-url { color: #00FF00 !important; }
.block-row--details .block-url { background: #1A1A1A !important; }
.block-row--details .block-url:hover { background: #00FF00 !important; color: #000000 !important; }
.btn-singleview { background: #000000 !important; color: #00FF00 !important; border: 1px solid #00FF00 !important; }
.btn-singleview:hover { background: #00FF00 !important; color: #000000 !important; }
.btn-spread-on, .content-actions .btn-pin-on { background: #00FF00 !important; color: #000000 !important; }
.btn-spread-on:hover, .content-actions .btn-pin-on:hover { background: #66FF66 !important; color: #000000 !important; }
.btn-back { background: #000000 !important; color: #00FF00 !important; border: 1px solid #00FF00 !important; }
.btn-back:hover { background: #00FF00 !important; color: #000000 !important; }
.block-info-table td, .pm-info-table td { border-color: #00FF00 !important; }
.block-diagram { border-color: #00FF00 !important; background: #000000 !important; }
.block-diagram-ruler { color: #00FF00 !important; background: #000000 !important; border-bottom-color: #00FF00 !important; }
.block-diagram-ruler span { color: #00FF00 !important; }
.block-diagram-cell { border-color: #00FF00 !important; background: #1A1A1A !important; }
.bd-label { color: #00FF00 !important; }
.bd-value { color: #00FF00 !important; }
.deleted-label { color: #ff3333 !important; }
/* Tribes */
.tribe-card { background: #1A1A1A !important; border-color: #00FF00 !important; }
.tribe-card:hover { box-shadow: 0 0 15px rgba(0,255,0,0.3) !important; }
.tribe-card-title { color: #00FF00 !important; }
.tribe-card-description { color: #00FF00 !important; }
.tribe-info-table td { border-color: #00FF00 !important; }
.tribe-info-label { color: #00FF00 !important; background: #1A1A1A !important; }
.tribe-info-value { color: #00FF00 !important; background: #1A1A1A !important; }
.tribe-info-empty { color: #006600 !important; }
.tribe-card-members { border-color: #00FF00 !important; background: #1A1A1A !important; }
.tribe-members-count { color: #00FF00 !important; }
.tribe-card-actions { border-color: #00FF00 !important; background: #1A1A1A !important; }
.tribe-action-btn { border-color: #00FF00 !important; color: #00FF00 !important; }
.tribe-action-btn:hover { background: #00FF00 !important; color: #000 !important; }
.tribe-subtribe-link { background: #000000 !important; border-color: #00FF00 !important; color: #00FF00 !important; }
.tribe-thumb-link { border-color: #00FF00 !important; }
.tribe-thumb-link:hover { box-shadow: 0 0 10px rgba(0,255,0,0.3) !important; }
.tribe-subtribe-link:hover { background: #00FF00 !important; color: #000 !important; }
.tribe-parent-image { border-color: #00FF00 !important; }
.tribe-parent-box { background: #1A1A1A !important; }
.oasis-nav-header { color: #00FF00 !important; border-color: #00FF00 !important; background: #000000 !important; }
.oasis-nav-header:hover { color: #000000 !important; background: #00FF00 !important; }
.oasis-nav-header .emoji, .oasis-nav-header .nav-text, .oasis-nav-arrow { color: inherit !important; }
.oasis-nav-list li a { color: #00FF00 !important; }
.oasis-nav-list li a:hover { color: #00FF00 !important; opacity: 1 !important; }
.oasis-nav-list .emoji, .oasis-nav-list .nav-text { color: inherit !important; }
nav, .sidebar-left nav, .sidebar-right nav, .sidebar-left ul, .sidebar-right ul { color: #00FF00 !important; }
.sidebar-left a, .sidebar-right a { color: #00FF00 !important; }
.ai-ask-form .ai-ask-input, .ai-ask-form .ai-ask-btn { color: #00FF00 !important; border-color: #00FF00 !important; background: #000000 !important; }
.ai-ask-form .ai-ask-input::placeholder { color: rgba(0,255,0,0.55) !important; }
.ai-ask-form .ai-ask-input:focus { border-color: #00FF00 !important; background: #1A1A1A !important; box-shadow: 0 0 6px rgba(0,255,0,0.4) !important; }
.ai-ask-form .ai-ask-btn:hover { background: #00FF00 !important; color: #000000 !important; border-color: #00FF00 !important; }
.ai-nav-results, .ai-nav-result-card { color: #00FF00 !important; border-color: #00FF00 !important; background: #000000 !important; }
.ai-nav-result-card .card-label { color: #00FF00 !important; }
.ai-nav-result-card a { color: #00FF00 !important; }
.ai-nav-result-card a:hover { background: #00FF00 !important; color: #000000 !important; }
.ai-nav-query { color: #00FF00 !important; }
.trending-card.own-content { box-shadow: inset 3px 0 0 #00FF00; }

View file

@ -0,0 +1,398 @@
body {
background-color: #4B0A6D;
color: #E5E5E5;
font-family: 'Arial', sans-serif;
}
footer {
border-top: 2px solid #9B1C96;
}
.sidebar-left, .sidebar-right {
background-color: #39006D;
border: 1px solid #9B1C96;
color: #E5E5E5;
padding: 15px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}
.main-column {
background-color: #1A1A1A;
border: 1px solid #9B1C96;
padding: 20px;
color: #E5E5E5;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}
button, input[type="submit"], input[type="button"] {
background-color: #9B1C96;
color: #E5E5E5;
border: 2px solid #6A0066;
border-radius: 10px;
padding: 12px 24px;
cursor: pointer;
}
button:hover, input[type="submit"]:hover, input[type="button"]:hover {
background-color: #6A0066;
border-color: #9B1C96;
box-shadow: 0 0 15px rgba(155, 28, 150, 0.8);
}
input, textarea, select {
background-color: #333333;
color: #E5E5E5;
border: 1px solid #9B1C96;
border-radius: 5px;
padding: 12px;
}
input:focus, textarea:focus, select:focus {
background-color: #39006D;
outline: none;
}
a {
color: #9B1C96;
text-decoration: none;
}
a:hover {
color: #E5E5E5;
}
table {
background-color: #1A1A1A;
color: #E5E5E5;
width: 100%;
border-collapse: collapse;
}
table th {
background-color: #6A0066;
}
table tr:nth-child(even) {
background-color: #333333;
}
nav ul {
background-color: #39006D;
padding: 0;
margin: 0;
list-style: none;
}
nav ul li {
display: inline-block;
margin-right: 10px;
}
nav ul li a {
color: #E5E5E5;
padding: 15px;
display: inline-block;
text-transform: none;
font-weight: bold;
letter-spacing: 0;
}
.profile {
background-color: #333333;
color: #E5E5E5;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
}
.profile .name {
color: #9B1C96;
font-size: 20px;
font-weight: bold;
}
.avatar {
border: 4px solid #9B1C96;
border-radius: 50%;
width: 80px;
height: 80px;
margin-bottom: 10px;
}
article, section {
background-color: #333333;
color: #E5E5E5;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
}
.post-preview {
background-color: #39006D;
padding: 15px;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
}
.post-preview img {
border-radius: 8px;
max-width: 100%;
}
::-webkit-scrollbar-thumb {
background-color: #9B1C96;
}
::-webkit-scrollbar-track {
background-color: #1A1A1A;
}
.action-container {
background-color: #333333;
border-color: #9B1C96;
color: #E5E5E5;
}
footer a {
background-color: #9B1C96;
color: #FFFFFF;
padding: 8px 20px;
border-radius: 5px;
text-decoration: none;
}
footer a:hover {
background-color: #6A0066;
}
.sidebar-left nav ul li a,
.sidebar-right nav ul li a,
.header nav ul li a {
background-color: #682B94 !important;
color: #FFE082 !important;
border: 1px solid #B86ADE !important;
font-weight: 600;
border-radius: 6px;
padding: 12px 16px;
display: flex;
justify-content: flex-start;
box-sizing: border-box;
transition: background-color 0.2s ease, border-color 0.2s ease;
}
.sidebar-left nav ul li a:hover,
.sidebar-right nav ul li a:hover,
.header nav ul li a:hover {
background-color: #682B94 !important;
border-color: #FFD54F !important;
color: #FFFFFF !important;
}
body {
background-color: #2D0B47 !important;
}
.main-column,
article,
section,
.action-container,
.profile,
.post-preview {
background-color: #3C1360 !important;
border-color: #B86ADE !important;
color: #FFEEDB !important;
}
input,
textarea,
select {
background-color: #4B1A72 !important;
color: #FFFFFF !important;
border-color: #BB5EFF !important;
}
button,
input[type="submit"],
input[type="button"] {
background-color: #A34AD8 !important;
color: #FFFFFF !important;
border-color: #751E9F !important;
}
header {
background-color: #5A1A85 !important;
border-bottom: 1px solid #B86ADE !important;
box-shadow: none !important;
}
.header {
background-color: #5A1A85 !important;
}
.top-bar-left,
.top-bar-mid,
.top-bar-right {
background-color: #39006D !important;
border: 1px solid #9B1C96 !important;
padding: 15px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
display: flex;
gap: 12px;
border-radius: 10px;
}
.sidebar-left,
.sidebar-right {
padding: 16px;
box-sizing: border-box;
}
.sidebar-left nav ul,
.sidebar-right nav ul {
display: flex;
flex-direction: column;
gap: 10px;
margin: 0;
padding: 0;
}
.sidebar-left nav ul li,
.sidebar-right nav ul li {
width: 100%;
}
.card {
color: #E5E5E5;
box-shadow: 0 4px 30px 0 rgba(0, 0, 0, 0.2);
background-color: #3C1360;
border-color: #B86ADE;
}
.card-label {
color: #9B1C96;
}
.card-footer {
color: #B86ADE;
}
.card-tags a.tag-link {
color: #FFFFFF;
background: #D94F4F;
}
.card-tags a.tag-link:hover {
background: #B86ADE;
color: #E5E5E5;
cursor: pointer;
}
a.user-link {
background-color: #FFD600;
color: #3C1360;
border-color: #FFD600;
transition: background-color 0.3s, color 0.3s, border-color 0.3s;
}
a.user-link:hover {
background-color: #FFB600;
border-color: #FFB600;
color: #3C1360;
cursor: pointer;
}
a.user-link:focus {
background-color: #9A2F2F;
border-color: #9A2F2F;
color: #E5E5E5;
}
.date-link {
background-color: #2F3C32;
color: #fff;
}
.date-link:hover {
background-color: #3E4A3D;
color: #fff;
}
.activitySpreadInhabitant2 {
background-color: #3E4A3D;
color: #fff;
}
.activityVotePost {
background-color: #3B5C42;
color: #fff;
}
.update-banner {
background-color: #1a0025;
border-bottom-color: #3d004d;
color: #E5E5E5;
}
.update-banner-link {
color: #c44bc1;
}
.snh-invite-code {
color: #9B1C96 !important;
}
.stats-kpi-label { color: #B86ADE !important; }
.stats-kpi-value { color: #FFEEDB !important; }
.carbon-bar-note, .carbon-bar-formula { color: #FFEEDB !important; }
.graphos-node-label { fill: #FFEEDB !important; }
.graphos-node-label-me { fill: #ffa500 !important; }
.graphos-legend { color: #FFEEDB !important; }
/* Blockexplorer */
.blockchain-view { background-color: #2D0B47 !important; color: #FFEEDB !important; }
.block { background: #3C1360 !important; border: 1px solid #B86ADE !important; }
.block:hover { box-shadow: 0 0 15px rgba(184,106,222,0.3) !important; }
.blockchain-card-label, .block-info-table .card-label, .pm-info-table .card-label, .block-content-label { color: #B86ADE !important; }
.blockchain-card-value, .block-info-table .card-value, .pm-info-table .card-value, .block-timestamp, .json-content { color: #FFEEDB !important; }
.block-content-preview, .block-content { background: #4B1A72 !important; color: #FFEEDB !important; }
.block-author { color: #FFD600 !important; background: rgba(255,214,0,0.08) !important; }
.block-author:hover { color: #FFB600 !important; }
.block-url { color: #B86ADE !important; }
.block-row--details .block-url { background: #4B1A72 !important; }
.block-row--details .block-url:hover { background: #5A1A85 !important; color: #FFD600 !important; }
.btn-singleview { background: #4B1A72 !important; color: #B86ADE !important; }
.btn-singleview:hover { background: #5A1A85 !important; color: #FFD600 !important; }
.btn-spread-on, .content-actions .btn-pin-on { background: #B86ADE !important; color: #2A0E42 !important; }
.btn-spread-on:hover, .content-actions .btn-pin-on:hover { background: #CE8CE9 !important; color: #2A0E42 !important; }
.btn-back { background: #A34AD8 !important; color: #FFFFFF !important; }
.btn-back:hover { background: #751E9F !important; color: #FFFFFF !important; }
.block-info-table td, .pm-info-table td { border-color: #B86ADE !important; }
.block-diagram { border-color: #B86ADE !important; background: #2D0B47 !important; }
.block-diagram-ruler { color: #B86ADE !important; background: #1A0030 !important; border-bottom-color: #B86ADE !important; }
.block-diagram-ruler span { color: #B86ADE !important; }
.block-diagram-cell { border-color: #B86ADE !important; background: #3C1360 !important; }
.bd-label { color: #B86ADE !important; }
.bd-value { color: #FFEEDB !important; }
.deleted-label { color: #ff5555 !important; }
/* Tribes */
.tribe-card { background: #3C1360 !important; border-color: #B86ADE !important; }
.tribe-card:hover { box-shadow: 0 0 15px rgba(184,106,222,0.3) !important; }
.tribe-card-title { color: #FFEEDB !important; }
.tribe-card-description { color: #FFEEDB !important; }
.tribe-info-table td { border-color: #B86ADE !important; }
.tribe-info-label { color: #B86ADE !important; background: #3C1360 !important; }
.tribe-info-value { color: #FFEEDB !important; background: #3C1360 !important; }
.tribe-info-empty { color: #8844aa !important; }
.tribe-card-members { border-color: #B86ADE !important; background: #2D0B47 !important; }
.tribe-members-count { color: #FFD600 !important; }
.tribe-card-actions { border-color: #B86ADE !important; background: #2D0B47 !important; }
.tribe-action-btn { border-color: #B86ADE !important; color: #B86ADE !important; }
.tribe-action-btn:hover { background: #B86ADE !important; color: #000 !important; }
.tribe-subtribe-link { background: #4B1A72 !important; border-color: #B86ADE !important; color: #FFD600 !important; }
.tribe-thumb-link { border-color: #B86ADE !important; }
.tribe-thumb-link:hover { border-color: #FFD600 !important; }
.tribe-subtribe-link:hover { background: #5A1A85 !important; }
.tribe-parent-image { border-color: #B86ADE !important; }
.tribe-parent-box { background: #3C1360 !important; }
.trending-card.own-content { box-shadow: inset 3px 0 0 #B86ADE; }

View file

@ -11,6 +11,7 @@
module.exports = {
en: {
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
bbFull: "Maximum reached",
@ -54,6 +55,7 @@ module.exports = {
spreadMore: "more"
},
es: {
chatReply: "Responder",
bbAdd: "Añadir",
bbDone: "Hecho",
bbFull: "Máximo alcanzado",
@ -102,6 +104,7 @@ module.exports = {
totalspreads: "Replicas totales"
},
fr: {
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
bbFull: "Maximum reached",
@ -145,6 +148,7 @@ module.exports = {
spreadMore: "plus"
},
eu: {
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
bbFull: "Maximum reached",
@ -188,6 +192,7 @@ module.exports = {
spreadMore: "gehiago"
},
de: {
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
bbFull: "Maximum reached",
@ -231,6 +236,7 @@ module.exports = {
spreadMore: "mehr"
},
it: {
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
bbFull: "Maximum reached",
@ -274,6 +280,7 @@ module.exports = {
spreadMore: "altro"
},
pt: {
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
bbFull: "Maximum reached",
@ -317,6 +324,7 @@ module.exports = {
spreadMore: "mais"
},
zh: {
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
bbFull: "Maximum reached",
@ -360,6 +368,7 @@ module.exports = {
spreadMore: "更多"
},
ar: {
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
bbFull: "Maximum reached",
@ -403,6 +412,7 @@ module.exports = {
spreadMore: "المزيد"
},
hi: {
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
bbFull: "Maximum reached",
@ -446,6 +456,7 @@ module.exports = {
spreadMore: "और"
},
ru: {
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
bbFull: "Maximum reached",

View file

@ -116,8 +116,8 @@ module.exports = ({ host, port, middleware, allowHost }) => {
app.use(koaStatic(path.join(__dirname, 'public')));
app.use(async (ctx, next) => {
//console.log("Requesting:", ctx.path); // uncomment to check for HTTP requests
if (httpDebug) console.log(`[http] ${ctx.method} ${ctx.path}`);
const isClearnet = isClearnetPath(ctx.request);
const csp = isClearnet

View file

@ -0,0 +1,76 @@
document.addEventListener('DOMContentLoaded', () => {
if (typeof pdfjsLib === 'undefined') return;
pdfjsLib.GlobalWorkerOptions.workerSrc = '/js/pdf.worker.min.mjs';
document.querySelectorAll('.pdf-viewer-container').forEach(async container => {
const pdfUrl = container.getAttribute('data-pdf-url');
if (!pdfUrl) return;
const pdf = await pdfjsLib.getDocument(pdfUrl).promise;
let currentPage = 1;
let scale = 1.5;
let rotation = 0;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
container.innerHTML = '';
container.appendChild(canvas);
const controls = document.createElement('div');
controls.className = 'pdf-controls';
controls.innerHTML = `
<button id="prev">⬅️</button>
<button id="next">➡️</button>
<button id="zoomIn">🔍+</button>
<button id="zoomOut">🔍−</button>
<button id="rotate">↻</button>
<button id="download">⬇️</button>
<button id="fullscreen">🔲</button>
<button id="metadata">ℹ️</button>
`;
container.appendChild(controls);
const renderPage = async (num) => {
const page = await pdf.getPage(num);
const viewport = page.getViewport({ scale, rotation });
canvas.width = viewport.width;
canvas.height = viewport.height;
ctx.clearRect(0, 0, canvas.width, canvas.height);
await page.render({ canvasContext: ctx, viewport }).promise;
};
const goToPage = (delta) => {
const newPage = currentPage + delta;
if (newPage >= 1 && newPage <= pdf.numPages) {
currentPage = newPage;
renderPage(currentPage);
}
};
renderPage(currentPage);
controls.querySelector('#prev').onclick = () => goToPage(-1);
controls.querySelector('#next').onclick = () => goToPage(1);
controls.querySelector('#zoomIn').onclick = () => { scale += 0.2; renderPage(currentPage); };
controls.querySelector('#zoomOut').onclick = () => { scale = Math.max(0.5, scale - 0.2); renderPage(currentPage); };
controls.querySelector('#rotate').onclick = () => { rotation = (rotation + 90) % 360; renderPage(currentPage); };
controls.querySelector('#download').onclick = () => {
const a = document.createElement('a');
a.href = pdfUrl;
a.download = 'document.pdf';
a.click();
};
controls.querySelector('#fullscreen').onclick = () => {
if (canvas.requestFullscreen) canvas.requestFullscreen();
else if (canvas.webkitRequestFullscreen) canvas.webkitRequestFullscreen();
else if (canvas.mozRequestFullScreen) canvas.mozRequestFullScreen();
else if (canvas.msRequestFullscreen) canvas.msRequestFullscreen();
};
controls.querySelector('#metadata').onclick = async () => {
const info = await pdf.getMetadata();
alert(`Title: ${info.info.Title || 'N/A'}\nAuthor: ${info.info.Author || 'N/A'}\nPDF Producer: ${info.info.Producer || 'N/A'}`);
};
});
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long