From 736b528b99cbadff77655b3d918b9c5e94b68f35 Mon Sep 17 00:00:00 2001 From: SITO Date: Wed, 19 Aug 2026 00:30:55 +0200 Subject: [PATCH] karvan: darle sitio en el escritorio siguiendo el patron del dev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/backend/backend.js | 2 +- src/client/assets/styles/karvan.css | 88 +++++++++++++++++++ .../assets/translations/fork/i18n_fork.js | 22 +++++ src/views/main_views.js | 21 ++++- src/views/modules_view.js | 1 + 5 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 src/client/assets/styles/karvan.css diff --git a/src/backend/backend.js b/src/backend/backend.js index 6c69274..f11d2d7 100644 --- a/src/backend/backend.js +++ b/src/backend/backend.js @@ -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; }, {})); }) diff --git a/src/client/assets/styles/karvan.css b/src/client/assets/styles/karvan.css new file mode 100644 index 0000000..7620c14 --- /dev/null +++ b/src/client/assets/styles/karvan.css @@ -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; } diff --git a/src/client/assets/translations/fork/i18n_fork.js b/src/client/assets/translations/fork/i18n_fork.js index cda9b98..ad4a727 100644 --- a/src/client/assets/translations/fork/i18n_fork.js +++ b/src/client/assets/translations/fork/i18n_fork.js @@ -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", diff --git a/src/views/main_views.js b/src/views/main_views.js index f9058be..215a63d 100644 --- a/src/views/main_views.js +++ b/src/views/main_views.js @@ -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' diff --git a/src/views/modules_view.js b/src/views/modules_view.js index 606490d..857bc91 100644 --- a/src/views/modules_view.js +++ b/src/views/modules_view.js @@ -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 },