activistas: workflow por defecto, lanzador compacto y barra de 4 atajos
Con el workflow activistas caben todos los modulos en una pantalla: se quitan el filtro Personal/Social y los accesos de usuario avanzado (menciones, habitantes, perfil, CV, estadisticas, blockexplorer, modulos). Peers y la edicion de la barra pasan a Herramientas; la barra inferior se queda en los 4 atajos. La config de serie arranca ya con los modulos de activistas.
This commit is contained in:
parent
e01f718c1c
commit
ab9bfab09a
4 changed files with 68 additions and 64 deletions
|
|
@ -50,7 +50,7 @@ body { padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px)); }
|
||||||
background: #121212;
|
background: #121212;
|
||||||
border-bottom: 1px solid #333;
|
border-bottom: 1px solid #333;
|
||||||
}
|
}
|
||||||
body { padding-top: 84px; background: #121212; }
|
body { padding-top: 74px; background: #121212; }
|
||||||
|
|
||||||
.oasis-mobile-topbar .omt-logo, .oasis-mobile-topbar .omt-avatar { flex: 0 0 auto; }
|
.oasis-mobile-topbar .omt-logo, .oasis-mobile-topbar .omt-avatar { flex: 0 0 auto; }
|
||||||
.oasis-mobile-topbar .omt-logo img,
|
.oasis-mobile-topbar .omt-logo img,
|
||||||
|
|
@ -972,10 +972,10 @@ button, input[type="submit"], input[type="button"],
|
||||||
/* (topbar sin barra de búsqueda: vuelve el título "OASIS" — CSS .omt-title más arriba) */
|
/* (topbar sin barra de búsqueda: vuelve el título "OASIS" — CSS .omt-title más arriba) */
|
||||||
|
|
||||||
/* --- el lanzador va en el header (debajo de los 2 botones), solo en la home --- */
|
/* --- el lanzador va en el header (debajo de los 2 botones), solo en la home --- */
|
||||||
.header .launcher { width: 100%; max-width: 440px; box-sizing: border-box; margin: 34px auto 10px; padding: 0 14px; }
|
.header .launcher { width: 100%; max-width: 440px; box-sizing: border-box; margin: 4px auto 10px; padding: 0 14px; }
|
||||||
|
|
||||||
/* holgura bajo la topbar fija */
|
/* holgura bajo la topbar fija */
|
||||||
body { padding-top: 84px; }
|
body { padding-top: 74px; }
|
||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
FORK_IA_UX · Módulo KARVAN (mensajes temporales + WebRTC) — chat estilo burbujas
|
FORK_IA_UX · Módulo KARVAN (mensajes temporales + WebRTC) — chat estilo burbujas
|
||||||
|
|
|
||||||
|
|
@ -7,63 +7,63 @@
|
||||||
},
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"blogsMod": "on",
|
"blogsMod": "on",
|
||||||
"pollsMod": "on",
|
"pollsMod": "off",
|
||||||
"fediverseMod": "on",
|
"fediverseMod": "off",
|
||||||
"invitesMod": "on",
|
"invitesMod": "on",
|
||||||
"walletMod": "off",
|
"walletMod": "off",
|
||||||
"devMod": "off",
|
"devMod": "off",
|
||||||
"cipherMod": "on",
|
"cipherMod": "off",
|
||||||
"bookmarksMod": "on",
|
"bookmarksMod": "off",
|
||||||
"videosMod": "on",
|
"videosMod": "on",
|
||||||
"docsMod": "off",
|
"docsMod": "off",
|
||||||
"audiosMod": "on",
|
"audiosMod": "off",
|
||||||
"tagsMod": "on",
|
"tagsMod": "off",
|
||||||
"imagesMod": "on",
|
"imagesMod": "on",
|
||||||
"trendingMod": "on",
|
"trendingMod": "off",
|
||||||
"eventsMod": "on",
|
"eventsMod": "off",
|
||||||
"tasksMod": "on",
|
"tasksMod": "off",
|
||||||
"marketMod": "on",
|
"marketMod": "off",
|
||||||
"votesMod": "on",
|
"votesMod": "off",
|
||||||
"tribesMod": "on",
|
"tribesMod": "off",
|
||||||
"reportsMod": "on",
|
"reportsMod": "off",
|
||||||
"opinionsMod": "on",
|
"opinionsMod": "off",
|
||||||
"padsMod": "on",
|
"padsMod": "on",
|
||||||
"karvanMod": "on",
|
"karvanMod": "on",
|
||||||
"calendarsMod": "on",
|
"calendarsMod": "off",
|
||||||
"transfersMod": "off",
|
"transfersMod": "off",
|
||||||
"feedMod": "on",
|
"feedMod": "on",
|
||||||
"pixeliaMod": "off",
|
"pixeliaMod": "off",
|
||||||
"melodyMod": "on",
|
"melodyMod": "off",
|
||||||
"agendaMod": "on",
|
"agendaMod": "off",
|
||||||
"aiMod": "off",
|
"aiMod": "off",
|
||||||
"aiNavMod": "off",
|
"aiNavMod": "off",
|
||||||
"forumMod": "on",
|
"forumMod": "on",
|
||||||
"gamesMod": "off",
|
"gamesMod": "off",
|
||||||
"housingMod": "on",
|
"housingMod": "off",
|
||||||
"jobsMod": "on",
|
"jobsMod": "off",
|
||||||
"shopsMod": "on",
|
"shopsMod": "off",
|
||||||
"projectsMod": "on",
|
"projectsMod": "off",
|
||||||
"industryMod": "on",
|
"industryMod": "off",
|
||||||
"bankingMod": "off",
|
"bankingMod": "off",
|
||||||
"schoolMod": "on",
|
"schoolMod": "off",
|
||||||
"parliamentMod": "on",
|
"parliamentMod": "off",
|
||||||
"courtsMod": "off",
|
"courtsMod": "off",
|
||||||
"favoritesMod": "on",
|
"favoritesMod": "off",
|
||||||
"logsMod": "off",
|
"logsMod": "off",
|
||||||
"mapsMod": "off",
|
"mapsMod": "off",
|
||||||
"chatsMod": "on",
|
"chatsMod": "on",
|
||||||
"torrentsMod": "off",
|
"torrentsMod": "off",
|
||||||
"filesMod": "on",
|
"filesMod": "off",
|
||||||
"phoneMod": "on",
|
"phoneMod": "off",
|
||||||
"roomsMod": "on",
|
"roomsMod": "off",
|
||||||
"graphosMod": "on",
|
"graphosMod": "off",
|
||||||
"larpMod": "on",
|
"larpMod": "off",
|
||||||
"backupMod": "on",
|
"backupMod": "on",
|
||||||
"campaignsMod": "on",
|
"campaignsMod": "off",
|
||||||
"emergenciesMod": "on",
|
"emergenciesMod": "off",
|
||||||
"logisticsMod": "on",
|
"logisticsMod": "off",
|
||||||
"mailingMod": "on",
|
"mailingMod": "off",
|
||||||
"podcastsMod": "on",
|
"podcastsMod": "off",
|
||||||
"wikiMod": "on"
|
"wikiMod": "on"
|
||||||
},
|
},
|
||||||
"wallet": {
|
"wallet": {
|
||||||
|
|
@ -96,10 +96,10 @@
|
||||||
"pubMaxMB": 0
|
"pubMaxMB": 0
|
||||||
},
|
},
|
||||||
"bottomBarPins": [
|
"bottomBarPins": [
|
||||||
"search",
|
"activity",
|
||||||
"inbox",
|
"chats",
|
||||||
"publish",
|
"publish",
|
||||||
"activity"
|
"inbox"
|
||||||
],
|
],
|
||||||
"rtc": {
|
"rtc": {
|
||||||
"stun": [],
|
"stun": [],
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ const applyWorkflow = (cfg, workflow) => {
|
||||||
|
|
||||||
const FULL_WORKFLOW = { key: 'full', modules: ALL_MODULES };
|
const FULL_WORKFLOW = { key: 'full', modules: ALL_MODULES };
|
||||||
|
|
||||||
const WIZARD_WORKFLOWS = ['full', 'social', 'activists', 'kids', 'night', 'jobs', 'business', 'mobile'];
|
const WIZARD_WORKFLOWS = ['activists', 'full', 'social', 'kids', 'night', 'jobs', 'business', 'mobile'];
|
||||||
|
|
||||||
const wizardWorkflow = (key) => {
|
const wizardWorkflow = (key) => {
|
||||||
const k = String(key || '');
|
const k = String(key || '');
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,10 @@ const { a, button, div, form, h2, h3, img, input, label, nav, p, section, span }
|
||||||
const { getConfig } = require("../configs/config-manager.js");
|
const { getConfig } = require("../configs/config-manager.js");
|
||||||
const sharedState = require("../configs/shared-state");
|
const sharedState = require("../configs/shared-state");
|
||||||
|
|
||||||
|
// con pocos modulos activos (el workflow activistas) todo cabe en una pantalla:
|
||||||
|
// sobran el filtro Personal/Social y los accesos de usuario avanzado
|
||||||
|
const COMPACT_MAX = 16;
|
||||||
|
|
||||||
module.exports = ({ i18n }) => {
|
module.exports = ({ i18n }) => {
|
||||||
// === Oasis UX (portado de 0.8.7_UX): topbar + bottombar + lanzador ===
|
// === Oasis UX (portado de 0.8.7_UX): topbar + bottombar + lanzador ===
|
||||||
// topbar fija arriba: [logo] [Personal] [Community] [avatar] en una línea (sin título OASIS)
|
// topbar fija arriba: [logo] [Personal] [Community] [avatar] en una línea (sin título OASIS)
|
||||||
|
|
@ -23,7 +27,7 @@ module.exports = ({ i18n }) => {
|
||||||
return div(
|
return div(
|
||||||
{ class: "oasis-mobile-topbar" },
|
{ class: "oasis-mobile-topbar" },
|
||||||
a({ class: "omt-logo", href: "/" }, img({ src: "/assets/images/snh-oasis.jpg", alt: "Oasis" })),
|
a({ class: "omt-logo", href: "/" }, img({ src: "/assets/images/snh-oasis.jpg", alt: "Oasis" })),
|
||||||
div({ class: "omt-menus" },
|
isCompact() ? div({ class: "omt-menus" }) : div({ class: "omt-menus" },
|
||||||
a({ class: hiveFilter === "personal" ? "oasis-menu-btn active" : "oasis-menu-btn", href: hiveFilter === "personal" ? "/activity" : "/activity?hive=personal" }, span(i18n.menuPersonal || "Personal")),
|
a({ class: hiveFilter === "personal" ? "oasis-menu-btn active" : "oasis-menu-btn", href: hiveFilter === "personal" ? "/activity" : "/activity?hive=personal" }, span(i18n.menuPersonal || "Personal")),
|
||||||
a({ class: hiveFilter === "community" ? "oasis-menu-btn active" : "oasis-menu-btn", href: hiveFilter === "community" ? "/activity" : "/activity?hive=community" }, span(i18n.menuSocial || "Social"))
|
a({ class: hiveFilter === "community" ? "oasis-menu-btn active" : "oasis-menu-btn", href: hiveFilter === "community" ? "/activity" : "/activity?hive=community" }, span(i18n.menuSocial || "Social"))
|
||||||
),
|
),
|
||||||
|
|
@ -96,8 +100,8 @@ module.exports = ({ i18n }) => {
|
||||||
(badge && badge > 0) ? span({ class: "bb-badge" }, String(badge)) : "",
|
(badge && badge > 0) ? span({ class: "bb-badge" }, String(badge)) : "",
|
||||||
span({ class: "bb-lbl" }, label)
|
span({ class: "bb-lbl" }, label)
|
||||||
);
|
);
|
||||||
// FORK_IA_UX v4: barra PERSONALIZABLE (pins) + lápiz ✎ para editar (/settings/bottombar)
|
// barra PERSONALIZABLE: solo los pins (max 4). Editarla y Peers estan en el
|
||||||
// + par FIJO Peers/Invites a la derecha. Sin FAB "+". (restaurada de la versión que gustaba)
|
// lanzador (Herramientas): 7 botones abajo eran demasiados para un pulgar.
|
||||||
const MAX = 4;
|
const MAX = 4;
|
||||||
const pins = (cfg.bottomBarPins || [])
|
const pins = (cfg.bottomBarPins || [])
|
||||||
.map(key => PINNABLE_MODULES.find(m => m.key === key))
|
.map(key => PINNABLE_MODULES.find(m => m.key === key))
|
||||||
|
|
@ -106,18 +110,9 @@ module.exports = ({ i18n }) => {
|
||||||
const slots = pins.map(m => bbLink(
|
const slots = pins.map(m => bbLink(
|
||||||
m.href, m.glyph, i18n[m.labelKey] || m.key, m.key === 'inbox' ? inboxN : 0
|
m.href, m.glyph, i18n[m.labelKey] || m.key, m.key === 'inbox' ? inboxN : 0
|
||||||
));
|
));
|
||||||
const editSlot = a(
|
|
||||||
{ class: "bb-item bb-add", href: "/settings/bottombar" },
|
|
||||||
span({ class: "bb-ico" }, "✎"),
|
|
||||||
span({ class: "bb-lbl" }, i18n.bbManage || "Edit")
|
|
||||||
);
|
|
||||||
const pair = [ bbLink("/peers", "⧖", i18n.peers || "Peers") ];
|
|
||||||
if (modOn('invitesMod')) pair.push(bbLink("/invites", "ꔮ", i18n.invites || "Invites"));
|
|
||||||
return nav(
|
return nav(
|
||||||
{ class: "oasis-bottombar", attrs: { "aria-label": i18n.bbQuickActions || "Quick actions" } },
|
{ class: "oasis-bottombar", attrs: { "aria-label": i18n.bbQuickActions || "Quick actions" } },
|
||||||
...slots,
|
...slots
|
||||||
editSlot,
|
|
||||||
div({ class: "bb-pair" }, ...pair)
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -136,12 +131,12 @@ module.exports = ({ i18n }) => {
|
||||||
{ href: '/wiki', glyph: 'ꖿ', labelKey: 'wikiTitle', mod: 'wikiMod' },
|
{ href: '/wiki', glyph: 'ꖿ', labelKey: 'wikiTitle', mod: 'wikiMod' },
|
||||||
{ href: '/blogs', glyph: 'ꔫ', labelKey: 'blogTitle', mod: 'blogsMod' },
|
{ href: '/blogs', glyph: 'ꔫ', labelKey: 'blogTitle', mod: 'blogsMod' },
|
||||||
{ href: '/opinions', glyph: 'ꔍ', labelKey: 'opinionsTitle', mod: 'opinionsMod' },
|
{ href: '/opinions', glyph: 'ꔍ', labelKey: 'opinionsTitle', mod: 'opinionsMod' },
|
||||||
{ href: '/mentions', glyph: '✺', labelKey: 'mentions', mod: null },
|
{ href: '/mentions', glyph: '✺', labelKey: 'mentions', mod: null, extra: true },
|
||||||
{ href: '/tags', glyph: 'ꖶ', labelKey: 'tagsLabel', mod: 'tagsMod' },
|
{ href: '/tags', glyph: 'ꖶ', labelKey: 'tagsLabel', mod: 'tagsMod' },
|
||||||
{ href: '/trending', glyph: 'ꗝ', labelKey: 'trendingLabel', mod: 'trendingMod' },
|
{ href: '/trending', glyph: 'ꗝ', labelKey: 'trendingLabel', mod: 'trendingMod' },
|
||||||
{ href: '/maps', glyph: 'ꔌ', labelKey: 'mapsLabel', mod: 'mapsMod' },
|
{ href: '/maps', glyph: 'ꔌ', labelKey: 'mapsLabel', mod: 'mapsMod' },
|
||||||
{ href: '/graphos', glyph: '⌬', labelKey: 'modulesGraphosLabel', mod: 'graphosMod' },
|
{ href: '/graphos', glyph: '⌬', labelKey: 'modulesGraphosLabel', mod: 'graphosMod' },
|
||||||
{ href: '/inhabitants', glyph: 'ꖘ', labelKey: 'inhabitantsLabel', mod: null },
|
{ href: '/inhabitants', glyph: 'ꖘ', labelKey: 'inhabitantsLabel', mod: null, extra: true },
|
||||||
{ href: '/fediverse', glyph: 'ꗵ', labelKey: 'fediverseTimeline', mod: 'fediverseMod' } ] },
|
{ href: '/fediverse', glyph: 'ꗵ', labelKey: 'fediverseTimeline', mod: 'fediverseMod' } ] },
|
||||||
{ id: 'media', titleKey: 'menuMedia', side: 'community', mods: [
|
{ id: 'media', titleKey: 'menuMedia', side: 'community', mods: [
|
||||||
{ href: '/images', glyph: 'ꕥ', labelKey: 'imagesLabel', mod: 'imagesMod' },
|
{ href: '/images', glyph: 'ꕥ', labelKey: 'imagesLabel', mod: 'imagesMod' },
|
||||||
|
|
@ -182,36 +177,45 @@ module.exports = ({ i18n }) => {
|
||||||
{ href: '/banking', glyph: 'ꗴ', labelKey: 'bankingTitle', mod: 'bankingMod' },
|
{ href: '/banking', glyph: 'ꗴ', labelKey: 'bankingTitle', mod: 'bankingMod' },
|
||||||
{ href: '/transfers', glyph: 'ꘉ', labelKey: 'transfersTitle', mod: 'transfersMod' } ] },
|
{ href: '/transfers', glyph: 'ꘉ', labelKey: 'transfersTitle', mod: 'transfersMod' } ] },
|
||||||
{ id: 'personal', titleKey: 'menuPersonal', side: 'personal', mods: [
|
{ id: 'personal', titleKey: 'menuPersonal', side: 'personal', mods: [
|
||||||
{ href: '/profile', glyph: '⚉', labelKey: 'profile', mod: null },
|
{ href: '/profile', glyph: '⚉', labelKey: 'profile', mod: null, extra: true },
|
||||||
{ href: '/agenda', glyph: 'ꗤ', labelKey: 'agendaTitle', mod: 'agendaMod' },
|
{ href: '/agenda', glyph: 'ꗤ', labelKey: 'agendaTitle', mod: 'agendaMod' },
|
||||||
{ href: '/favorites', glyph: 'ꘝ', labelKey: 'favoritesTitle', mod: 'favoritesMod' },
|
{ href: '/favorites', glyph: 'ꘝ', labelKey: 'favoritesTitle', mod: 'favoritesMod' },
|
||||||
{ href: '/phone', glyph: '☏', labelKey: 'phoneTitle', mod: 'phoneMod' },
|
{ href: '/phone', glyph: '☏', labelKey: 'phoneTitle', mod: 'phoneMod' },
|
||||||
{ href: '/cv', glyph: 'ꕛ', labelKey: 'cvTitle', mod: null },
|
{ href: '/cv', glyph: 'ꕛ', labelKey: 'cvTitle', mod: null, extra: true },
|
||||||
{ href: '/wallet', glyph: '❄', labelKey: 'wallet', mod: 'walletMod' },
|
{ href: '/wallet', glyph: '❄', labelKey: 'wallet', mod: 'walletMod' },
|
||||||
{ href: '/logs', glyph: 'ꗯ', labelKey: 'logsTitle', mod: 'logsMod' } ] },
|
{ href: '/logs', glyph: 'ꗯ', labelKey: 'logsTitle', mod: 'logsMod' } ] },
|
||||||
{ id: 'tools', titleKey: 'menuTools', side: 'personal', mods: [
|
{ id: 'tools', titleKey: 'menuTools', side: 'personal', mods: [
|
||||||
{ href: '/invites', glyph: 'ꔹ', labelKey: 'invites', mod: 'invitesMod' },
|
{ href: '/invites', glyph: 'ꔹ', labelKey: 'invites', mod: 'invitesMod' },
|
||||||
|
{ href: '/peers', glyph: '⧖', labelKey: 'peers', mod: null },
|
||||||
|
{ href: '/settings/bottombar', glyph: '✎', labelKey: 'bbYourBar', mod: null },
|
||||||
{ href: '/backup', glyph: 'ꖤ', labelKey: 'backupTitle', mod: 'backupMod' },
|
{ href: '/backup', glyph: 'ꖤ', labelKey: 'backupTitle', mod: 'backupMod' },
|
||||||
{ href: '/cipher', glyph: 'ꗄ', labelKey: 'cipher', mod: 'cipherMod' },
|
{ href: '/cipher', glyph: 'ꗄ', labelKey: 'cipher', mod: 'cipherMod' },
|
||||||
{ href: '/ai', glyph: 'ꘜ', labelKey: 'ai', mod: 'aiMod' },
|
{ href: '/ai', glyph: 'ꘜ', labelKey: 'ai', mod: 'aiMod' },
|
||||||
{ href: '/stats', glyph: 'ꕷ', labelKey: 'statistics', mod: null },
|
{ href: '/stats', glyph: 'ꕷ', labelKey: 'statistics', mod: null, extra: true },
|
||||||
{ href: '/blockexplorer', glyph: 'ꖸ', labelKey: 'blockchain', mod: null },
|
{ href: '/blockexplorer', glyph: 'ꖸ', labelKey: 'blockchain', mod: null, extra: true },
|
||||||
{ href: '/modules', glyph: 'ꗣ', labelKey: 'modules', mod: null },
|
{ href: '/modules', glyph: 'ꗣ', labelKey: 'modules', mod: null, extra: true },
|
||||||
{ href: '/settings', glyph: '⚙', labelKey: 'settings', mod: null } ] },
|
{ href: '/settings', glyph: '⚙', labelKey: 'settings', mod: null } ] },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const isCompact = () => {
|
||||||
|
const cfg = getConfig();
|
||||||
|
const on = (m) => m && cfg.modules[m] === 'on';
|
||||||
|
return GROUPS.reduce((n, g) => n + g.mods.filter(x => on(x.mod)).length, 0) <= COMPACT_MAX;
|
||||||
|
};
|
||||||
|
|
||||||
const renderHiveNav = () => {
|
const renderHiveNav = () => {
|
||||||
if (process.env.OASIS_MOBILE !== '1') return "";
|
if (process.env.OASIS_MOBILE !== '1') return "";
|
||||||
const cfg = getConfig();
|
const cfg = getConfig();
|
||||||
const modOn = (m) => !m || cfg.modules[m] === 'on' || cfg.modules[m] === undefined;
|
const modOn = (m) => !m || cfg.modules[m] === 'on' || cfg.modules[m] === undefined;
|
||||||
|
const compact = isCompact();
|
||||||
// Personal/Social de la topbar (lo pone el middleware desde ?hive=) parte el lanzador en dos
|
// Personal/Social de la topbar (lo pone el middleware desde ?hive=) parte el lanzador en dos
|
||||||
const hiveFilter = (typeof global !== "undefined" && global.__OASIS_HIVE_FILTER__) || "";
|
const hiveFilter = compact ? "" : ((typeof global !== "undefined" && global.__OASIS_HIVE_FILTER__) || "");
|
||||||
const app = (m) => a({ class: 'ln-app', href: m.href },
|
const app = (m) => a({ class: 'ln-app', href: m.href },
|
||||||
span({ class: 'ln-ico', 'aria-hidden': 'true' }, m.glyph),
|
span({ class: 'ln-ico', 'aria-hidden': 'true' }, m.glyph),
|
||||||
span({ class: 'ln-lbl' }, i18n[m.labelKey] || m.href.slice(1)));
|
span({ class: 'ln-lbl' }, i18n[m.labelKey] || m.href.slice(1)));
|
||||||
const groups = GROUPS
|
const groups = GROUPS
|
||||||
.filter(g => !hiveFilter || g.side === hiveFilter)
|
.filter(g => !hiveFilter || g.side === hiveFilter)
|
||||||
.map(g => ({ g, mods: g.mods.filter(m => modOn(m.mod)) }))
|
.map(g => ({ g, mods: g.mods.filter(m => modOn(m.mod) && !(compact && m.extra)) }))
|
||||||
.filter(x => x.mods.length);
|
.filter(x => x.mods.length);
|
||||||
return nav({ class: 'launcher', 'aria-label': i18n.modules || 'Modules' },
|
return nav({ class: 'launcher', 'aria-label': i18n.modules || 'Modules' },
|
||||||
...groups.map(({ g, mods }) => div({ class: 'ln-group' },
|
...groups.map(({ g, mods }) => div({ class: 'ln-group' },
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue