karvan: darle sitio en el escritorio siguiendo el patron del dev

Karvan solo existia en la rejilla de hexagonos, que es de movil. En escritorio no
habia forma de llegar salvo escribiendo la URL.

Se anade renderKarvanLink en main_views, calcado de renderPollsLink —misma forma,
mismo checkMod por getConfig().modules, mismo navLink— y se invoca en el grupo
social junto a renderChatsLink. Entra tambien en modules_view y en la lista de
/modules de backend.js, para poder apagarlo como cualquier otro modulo, con sus
etiquetas en el overlay.

Los estilos del modulo pasan a src/client/assets/styles/karvan.css. Estaban dentro
de OasisMobile.css, que en escritorio no se carga, asi que las salas se habrian
visto sin formato. Va como hoja propia siguiendo el patron de highlight.css, que
tampoco pertenece a ningun tema: asi el modulo se ve igual con cualquier tema y en
las dos plataformas.

Verificado: karvan.css sirve 200 y se carga en las dos plantillas, el enlace aparece
en el menu lateral, y en movil la rejilla de hexagonos sigue igual.
This commit is contained in:
SITO 2026-08-19 00:30:55 +02:00
parent 841acf2a7a
commit 736b528b99
5 changed files with 132 additions and 2 deletions

View file

@ -1806,7 +1806,7 @@ router
ctx.body = statsView(stats, filter);
})
.get("/modules", async (ctx) => {
const modules = ['blogs', 'polls', 'fediverse', 'invites', 'wallet', 'legacy', 'dev', 'cipher', 'bookmarks', 'calendars', 'chats', 'videos', 'docs', 'audios', 'tags', 'images', 'maps', 'trending', 'events', 'tasks', 'market', 'tribes', 'larp', 'votes', 'reports', 'opinions', 'pads', 'transfers', 'feed', 'pixelia', 'melody', 'agenda', 'favorites', 'ai', 'forum', 'games', 'housing', 'jobs', 'projects', 'industry', 'shops', 'banking', 'parliament', 'courts'];
const modules = ['blogs', 'polls', 'karvan', 'fediverse', 'invites', 'wallet', 'legacy', 'dev', 'cipher', 'bookmarks', 'calendars', 'chats', 'videos', 'docs', 'audios', 'tags', 'images', 'maps', 'trending', 'events', 'tasks', 'market', 'tribes', 'larp', 'votes', 'reports', 'opinions', 'pads', 'transfers', 'feed', 'pixelia', 'melody', 'agenda', 'favorites', 'ai', 'forum', 'games', 'housing', 'jobs', 'projects', 'industry', 'shops', 'banking', 'parliament', 'courts'];
const cfg = getConfig().modules;
ctx.body = modulesView(modules.reduce((acc, m) => { acc[`${m}Mod`] = cfg[`${m}Mod`]; return acc; }, {}));
})

View file

@ -0,0 +1,88 @@
/* Estilos del modulo Karvan (salas efimeras y llamadas).
*
* Viven aparte del tema para que el modulo se vea igual en cualquier tema y
* tambien en escritorio, donde OasisMobile.css no se carga. Mismo patron que
* highlight.css, que tampoco pertenece a ningun tema concreto.
*/
/* --- Reply a mensaje en chats (server-side ?replyTo=, sin JS) --- */
.chat-message-meta .chat-reply-btn { margin-left: auto; padding: 0 4px; color: #FFD700; text-decoration: none; font-size: 15px; opacity: .85; }
.chat-message-self .chat-message-meta .chat-reply-btn { margin-left: 8px; }
.chat-quote {
display: block; border-left: 3px solid #FFD700; padding: 3px 8px; margin: 0 0 5px;
background: rgba(255,215,0,.08); border-radius: 6px; font-size: 12px; line-height: 1.3;
}
.chat-quote-author, .chat-quote-author a { color: #FFD700; font-weight: 700; margin-right: 6px; }
.chat-quote-text { color: #FFDD44; }
.chat-replying-to {
display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
border-left: 3px solid #FFD700; background: rgba(255,215,0,.10);
padding: 6px 10px; margin-bottom: 8px; border-radius: 8px; font-size: 12px;
}
.chat-replying-label { color: #FFD700; font-weight: 700; }
.chat-reply-cancel { margin-left: auto; color: #FFD700; text-decoration: none; font-weight: 700; font-size: 14px; }
/* ==========================================================================
FORK_IA_UX · Módulo KARVAN (mensajes temporales + WebRTC) chat estilo burbujas
========================================================================== */
.karvan-intro h2 { color: #FFD700; margin: 0 0 6px; }
.karvan-sub { color: #FFDD44; font-size: 13px; }
.karvan-create input[type="text"] { width: 100%; box-sizing: border-box; padding: 10px 12px;
background: #161616; border: 1px solid #333; border-radius: 10px; color: #FFD700; }
.karvan-ttl { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin: 10px 0; }
.karvan-ttl-lbl { color: #FFDD44; font-size: 13px; }
.karvan-ttl-opt { display: inline-flex; align-items: center; gap: 4px; color: #FFD700; font-size: 13px; }
.karvan-create button, .karvan-compose button { padding: 10px 16px; border: 1px solid #FFD700;
border-radius: 10px; background: #FFD700; color: #121212; font-weight: 700; cursor: pointer; }
.karvan-rooms { list-style: none; margin: 8px 0 0; padding: 0; }
.karvan-rooms li { margin: 0 0 8px; }
.karvan-room-item { display: flex; justify-content: space-between; align-items: center; gap: 10px;
padding: 12px 14px; background: #161616; border: 1px solid #333; border-radius: 12px;
color: #FFD700; text-decoration: none; min-height: 48px; box-sizing: border-box; }
.karvan-room-item .kr-title { font-weight: 600; }
.karvan-room-item .kr-meta { color: #FFDD44; font-size: 12px; white-space: nowrap; }
.karvan-empty { color: #FFDD44; }
/* sala */
.karvan-room-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.karvan-back { color: #FFD700; text-decoration: none; font-weight: 600; }
.karvan-room-title { flex: 1 1 auto; color: #FFD700; font-weight: 700; text-align: center;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.karvan-expire { color: #FFDD44; font-size: 12px; white-space: nowrap; }
.karvan-live { display: inline-flex; align-items: center; gap: 6px; color: #FFDD44; font-size: 12px; margin-bottom: 8px; }
.karvan-live .kl-dot { width: 8px; height: 8px; border-radius: 50%; background: #777; }
.karvan-live.on .kl-dot { background: #35d07f; }
.karvan-live.on .kl-txt { color: #35d07f; }
.karvan-msgs { list-style: none; margin: 0; padding: 6px 0; display: flex; flex-direction: column; gap: 6px;
max-height: 58vh; overflow-y: auto; }
.karvan-msg { max-width: 82%; align-self: flex-start; background: #1c1c1c; border: 1px solid #333;
border-radius: 14px; padding: 7px 11px; box-sizing: border-box; }
.karvan-msg-self { align-self: flex-end; background: #2a2412; border-color: #FFD700; }
.karvan-msg-live { border-left: 2px solid #35d07f; }
.karvan-msg .km-from { display: block; font-size: 10px; color: #FFDD44; margin-bottom: 2px; }
.karvan-msg .km-text { color: #FFD700; word-break: break-word; }
.karvan-compose { display: flex; gap: 8px; margin-top: 10px; }
.karvan-compose input[type="text"] { flex: 1 1 auto; min-width: 0; padding: 10px 12px;
background: #161616; border: 1px solid #333; border-radius: 10px; color: #FFD700; }
/* Fase 2: invitar a un contacto por feed id */
.karvan-invite { display: flex; gap: 8px; margin-top: 8px; }
.karvan-invite input[type="text"] { flex: 1 1 auto; min-width: 0; padding: 9px 12px;
background: #161616; border: 1px solid #333; border-radius: 10px; color: #FFD700; font-family: monospace; font-size: 12px; }
.karvan-invite button { flex: 0 0 auto; padding: 9px 14px; border: 1px solid #FFD700; background: #161616; color: #FFD700; border-radius: 10px; cursor: pointer; }
.karvan-invite-msg { font-size: 12px; margin: 6px 0 0; }
.karvan-invite-msg.ok { color: #35d07f; }
.karvan-invite-msg.err { color: #ff8a8a; }
/* --- Karvan videollamada (Fase 1): media P2P sobre el mismo WebRTC del chat --- */
.karvan-call, .karvan-videos, .karvan-call-bar, .kc-status {
background-color: transparent; box-shadow: none; border-radius: 0; padding: 0; margin: 0; /* anular div{#222}
.karvan-call { margin: 10px 0; }
.karvan-videos { display: none; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 6px; margin-bottom: 8px; }
.karvan-call.active .karvan-videos { display: grid; }
.kc-video { width: 100%; aspect-ratio: 4 / 3; background: #000; border-radius: 10px; border: 1px solid #333; object-fit: cover; display: block; }
.kc-local { transform: scaleX(-1); }
.kc-remote { display: contents; }
.karvan-call-bar { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.kc-btn { min-height: 44px; min-width: 44px; padding: 8px 12px; border-radius: 999px;
border: 1px solid #333; background: #161616; color: #FFD700; line-height: 1; cursor: pointer; }
.kc-btn.on { background: #FFD700; color: #121212; border-color: #FFD700; }
.kc-btn-start { font-weight: 600; }
.kc-btn-stop { background: #241414; border-color: #5a2a2a; }
.kc-status { font-size: 12px; color: #FFDD44; margin-top: 6px; min-height: 14px; }

View file

@ -11,6 +11,8 @@
module.exports = {
en: {
modulesKarvanLabel: "Karvan",
modulesKarvanDescription: "Ephemeral rooms: messages live only in memory and self-destruct.",
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
@ -55,6 +57,8 @@ module.exports = {
spreadMore: "more"
},
es: {
modulesKarvanLabel: "Karvan",
modulesKarvanDescription: "Salas efimeras: los mensajes viven solo en memoria y se autodestruyen.",
chatReply: "Responder",
bbAdd: "Añadir",
bbDone: "Hecho",
@ -104,6 +108,8 @@ module.exports = {
totalspreads: "Replicas totales"
},
fr: {
modulesKarvanLabel: "Karvan",
modulesKarvanDescription: "Ephemeral rooms: messages live only in memory and self-destruct.",
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
@ -148,6 +154,8 @@ module.exports = {
spreadMore: "plus"
},
eu: {
modulesKarvanLabel: "Karvan",
modulesKarvanDescription: "Ephemeral rooms: messages live only in memory and self-destruct.",
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
@ -192,6 +200,8 @@ module.exports = {
spreadMore: "gehiago"
},
de: {
modulesKarvanLabel: "Karvan",
modulesKarvanDescription: "Ephemeral rooms: messages live only in memory and self-destruct.",
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
@ -236,6 +246,8 @@ module.exports = {
spreadMore: "mehr"
},
it: {
modulesKarvanLabel: "Karvan",
modulesKarvanDescription: "Ephemeral rooms: messages live only in memory and self-destruct.",
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
@ -280,6 +292,8 @@ module.exports = {
spreadMore: "altro"
},
pt: {
modulesKarvanLabel: "Karvan",
modulesKarvanDescription: "Ephemeral rooms: messages live only in memory and self-destruct.",
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
@ -324,6 +338,8 @@ module.exports = {
spreadMore: "mais"
},
zh: {
modulesKarvanLabel: "Karvan",
modulesKarvanDescription: "Ephemeral rooms: messages live only in memory and self-destruct.",
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
@ -368,6 +384,8 @@ module.exports = {
spreadMore: "更多"
},
ar: {
modulesKarvanLabel: "Karvan",
modulesKarvanDescription: "Ephemeral rooms: messages live only in memory and self-destruct.",
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
@ -412,6 +430,8 @@ module.exports = {
spreadMore: "المزيد"
},
hi: {
modulesKarvanLabel: "Karvan",
modulesKarvanDescription: "Ephemeral rooms: messages live only in memory and self-destruct.",
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",
@ -456,6 +476,8 @@ module.exports = {
spreadMore: "और"
},
ru: {
modulesKarvanLabel: "Karvan",
modulesKarvanDescription: "Ephemeral rooms: messages live only in memory and self-destruct.",
chatReply: "Reply",
bbAdd: "Add",
bbDone: "Done",

View file

@ -537,6 +537,18 @@ const navGroup = ({ id, emoji, title, defaultOpen = false }, ...items) => {
const renderKarvanLink = () => {
const karvanMod = getConfig().modules.karvanMod === "on";
return karvanMod
? navLink({
href: "/karvan",
emoji: "⧗",
text: i18n.karvanTitle,
class: "karvan-link enabled"
})
: "";
};
const renderPollsLink = () => {
const pollsMod = getConfig().modules.pollsMod === "on";
return pollsMod
@ -1202,6 +1214,9 @@ const template = (titlePrefix, ...elements) => {
head(
title(titlePrefix, " | Oasis"),
link({ rel: "stylesheet", href: `/assets/styles/style.css?v=${assetVersion()}` }),
// el modulo Karvan trae su propia hoja: asi se ve igual en cualquier tema
// y tambien en escritorio, donde no se carga OasisMobile.css
link({ rel: "stylesheet", href: `/assets/styles/karvan.css?v=${assetVersion()}` }),
// movil: el tema va DESPUES de mobile.css para ganar por cascada sin !important;
// escritorio: orden original de epsylon
...(process.env.OASIS_MOBILE === '1'
@ -1507,7 +1522,8 @@ const template = (titlePrefix, ...elements) => {
renderPadsLink(),
renderForumLink(),
renderMapsLink(),
renderChatsLink()
renderChatsLink(),
renderKarvanLink()
),
navGroup(
{
@ -1563,6 +1579,9 @@ exports.ainavHomeView = ({ recentTags = [] } = {}) => {
head(
title(placeholder, " | Oasis"),
link({ rel: "stylesheet", href: `/assets/styles/style.css?v=${assetVersion()}` }),
// el modulo Karvan trae su propia hoja: asi se ve igual en cualquier tema
// y tambien en escritorio, donde no se carga OasisMobile.css
link({ rel: "stylesheet", href: `/assets/styles/karvan.css?v=${assetVersion()}` }),
// movil: el tema va DESPUES de mobile.css para ganar por cascada sin !important;
// escritorio: orden original de epsylon
...(process.env.OASIS_MOBILE === '1'

View file

@ -41,6 +41,7 @@ const modulesView = () => {
{ name: 'parliament', label: i18n.modulesParliamentLabel, description: i18n.modulesParliamentDescription },
{ name: 'pixelia', label: i18n.modulesPixeliaLabel, description: i18n.modulesPixeliaDescription },
{ name: 'polls', label: i18n.modulesPollsLabel, description: i18n.modulesPollsDescription },
{ name: 'karvan', label: i18n.modulesKarvanLabel, description: i18n.modulesKarvanDescription },
{ name: 'projects', label: i18n.modulesProjectsLabel, description: i18n.modulesProjectsDescription },
{ name: 'reports', label: i18n.modulesReportsLabel, description: i18n.modulesReportsDescription },
{ name: 'shops', label: i18n.modulesShopsLabel, description: i18n.modulesShopsDescription },