Configurable bottom bar and empty-state helper
- Bottom bar: replace Activity with a + slot to pin a module; hide slots for disabled modules. - Add a reusable empty-state helper and the inbox empty state. - Mobile styles and translations for the above.
This commit is contained in:
parent
851042e576
commit
9c100ed773
13 changed files with 252 additions and 10 deletions
|
|
@ -1531,3 +1531,58 @@ button, input[type="submit"], input[type="button"],
|
|||
.main-column { padding: 10px 12px 16px 12px !important; }
|
||||
.activity-filter-acc { margin-bottom: 4px !important; }
|
||||
|
||||
.empty-state {
|
||||
display: flex !important; flex-direction: column !important; align-items: center !important;
|
||||
justify-content: center !important; text-align: center !important;
|
||||
padding: 40px 16px !important; gap: 8px !important; width: 100% !important; box-sizing: border-box !important;
|
||||
}
|
||||
.empty-state-icon { font-size: 44px !important; line-height: 1 !important; opacity: 0.55 !important; }
|
||||
.empty-state-title { font-size: 16px !important; font-weight: 700 !important; margin: 4px 0 0 0 !important; color: #eee !important; }
|
||||
.empty-state-text { color: var(--c-muted, #8c8c8c) !important; font-size: 14px !important; line-height: 1.4 !important; max-width: 40ch !important; margin: 0 !important; }
|
||||
.empty-state-cta { margin-top: 10px !important; min-height: 48px !important; display: inline-flex !important; align-items: center !important; }
|
||||
|
||||
.activity-filter-collapsed {
|
||||
display: flex !important; align-items: center !important; gap: 10px !important;
|
||||
flex-wrap: wrap !important; margin-bottom: 8px !important; width: 100% !important;
|
||||
}
|
||||
.activity-back {
|
||||
display: inline-flex !important; align-items: center !important; gap: 4px !important;
|
||||
min-height: 44px !important; padding: 6px 14px 6px 10px !important; flex: 0 0 auto !important;
|
||||
}
|
||||
.activity-back-arrow { font-size: 22px !important; line-height: 1 !important; font-weight: bold !important; }
|
||||
.activity-active-filter {
|
||||
font-weight: 700 !important; color: #FFA500 !important; text-transform: uppercase !important;
|
||||
font-size: 13px !important; letter-spacing: .03em !important;
|
||||
}
|
||||
|
||||
.oasis-bottombar .bb-item { min-height: 48px !important; }
|
||||
.oasis-bottombar .bb-pair .bb-item { min-height: 44px !important; padding: 4px 10px !important; }
|
||||
.oasis-mobile-menus .oasis-menu-btn { min-height: 48px !important; }
|
||||
.pm-bubble .pm-actions .pm-btn { min-height: 40px !important; padding: 6px 12px !important; }
|
||||
.score-btn, .vote-btn, .feed-action-btn {
|
||||
min-height: 44px !important; min-width: 44px !important;
|
||||
display: inline-flex !important; align-items: center !important; justify-content: center !important;
|
||||
}
|
||||
.score-btn:active, .vote-btn:active, .feed-action-btn:active { filter: brightness(.85) !important; }
|
||||
|
||||
.oasis-bottombar .bb-add .bb-ico {
|
||||
background: #FFA500 !important; color: #121212 !important; border-radius: 999px !important;
|
||||
width: 30px !important; height: 30px !important; display: inline-flex !important;
|
||||
align-items: center !important; justify-content: center !important;
|
||||
font-weight: bold !important; font-size: 20px !important; line-height: 1 !important;
|
||||
}
|
||||
.bb-pick-grid {
|
||||
display: grid !important; grid-template-columns: repeat(3, 1fr) !important;
|
||||
gap: 8px !important; width: 100% !important; margin-top: 8px !important;
|
||||
}
|
||||
.bb-pick-form { margin: 0 !important; display: block !important; }
|
||||
.bb-pick-btn {
|
||||
display: flex !important; flex-direction: column !important; align-items: center !important;
|
||||
justify-content: center !important; gap: 6px !important; width: 100% !important;
|
||||
min-height: 76px !important; padding: 10px 6px !important; box-sizing: border-box !important;
|
||||
background: #1c1c1c !important; border: 1px solid #333 !important; border-radius: 12px !important; color: #eee !important;
|
||||
}
|
||||
.bb-pick-btn.active { border-color: #FFA500 !important; background: #2a2412 !important; }
|
||||
.bb-pick-ico { font-size: 26px !important; color: #FFA500 !important; line-height: 1 !important; }
|
||||
.bb-pick-lbl { font-size: 11px !important; text-align: center !important; line-height: 1.2 !important; }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
const { a, em, strong } = require('../../../server/node_modules/hyperaxe');
|
||||
module.exports = {
|
||||
ar: {
|
||||
bbAdd: "إضافة",
|
||||
bbQuickActions: "إجراءات سريعة",
|
||||
bbPickTitle: "تثبيت وحدة",
|
||||
bbPickDesc: "اختر وحدة لخانة + في الشريط السفلي.",
|
||||
bbPickNone: "لا شيء",
|
||||
activityChangeFilter: "تغيير التصفية",
|
||||
emptyConnectHint: "اتصل بـ pub للمزامنة مع الشبكة.",
|
||||
emptyConnectCta: "الاتصال بـ pub",
|
||||
menuCommunity: "المجتمع",
|
||||
activityGroupCommunity: "المجتمع والحوكمة",
|
||||
activityGroupOrg: "التنظيم",
|
||||
activityGroupComm: "التواصل",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
const { a, em, strong } = require('../../../server/node_modules/hyperaxe');
|
||||
module.exports = {
|
||||
de: {
|
||||
bbAdd: "Hinzufügen",
|
||||
bbQuickActions: "Schnellaktionen",
|
||||
bbPickTitle: "Modul anheften",
|
||||
bbPickDesc: "Wähle ein Modul für den +-Platz in der unteren Leiste.",
|
||||
bbPickNone: "Keins",
|
||||
activityChangeFilter: "Filter ändern",
|
||||
emptyConnectHint: "Verbinde dich mit einem Pub, um dich mit dem Netzwerk zu synchronisieren.",
|
||||
emptyConnectCta: "Mit einem Pub verbinden",
|
||||
menuCommunity: "Gemeinschaft",
|
||||
activityGroupCommunity: "Gemeinschaft & Governance",
|
||||
activityGroupOrg: "Organisation",
|
||||
activityGroupComm: "Kommunikation",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
const { a, em, strong } = require('../../../server/node_modules/hyperaxe');
|
||||
module.exports = {
|
||||
en: {
|
||||
bbAdd: "Add",
|
||||
bbQuickActions: "Quick actions",
|
||||
bbPickTitle: "Pin a module",
|
||||
bbPickDesc: "Choose a module for the + slot in the bottom bar.",
|
||||
bbPickNone: "None",
|
||||
activityChangeFilter: "Change filter",
|
||||
emptyConnectHint: "Connect to a pub to sync with the network.",
|
||||
emptyConnectCta: "Connect to a pub",
|
||||
menuCommunity: "Community",
|
||||
activityGroupCommunity: "Community & Governance",
|
||||
activityGroupOrg: "Organization",
|
||||
activityGroupComm: "Communication",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
const { a, em, strong } = require('../../../server/node_modules/hyperaxe');
|
||||
module.exports = {
|
||||
es: {
|
||||
bbAdd: "Añadir",
|
||||
bbQuickActions: "Acciones rápidas",
|
||||
bbPickTitle: "Fijar un módulo",
|
||||
bbPickDesc: "Elige un módulo para el hueco + de la barra inferior.",
|
||||
bbPickNone: "Ninguno",
|
||||
activityChangeFilter: "Cambiar filtro",
|
||||
emptyConnectHint: "Conéctate a un pub para sincronizar con la red.",
|
||||
emptyConnectCta: "Conéctate a un pub",
|
||||
menuCommunity: "Comunidad",
|
||||
activityGroupCommunity: "Comunidad y Gobernanza",
|
||||
activityGroupOrg: "Organización",
|
||||
activityGroupComm: "Comunicación",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
const { a, em, strong } = require('../../../server/node_modules/hyperaxe');
|
||||
module.exports = {
|
||||
eu: {
|
||||
bbAdd: "Gehitu",
|
||||
bbQuickActions: "Ekintza azkarrak",
|
||||
bbPickTitle: "Ainguratu modulu bat",
|
||||
bbPickDesc: "Aukeratu modulu bat beheko barrako + hutsunerako.",
|
||||
bbPickNone: "Bat ere ez",
|
||||
activityChangeFilter: "Aldatu iragazkia",
|
||||
emptyConnectHint: "Konektatu pub batera sarearekin sinkronizatzeko.",
|
||||
emptyConnectCta: "Konektatu pub batera",
|
||||
menuCommunity: "Komunitatea",
|
||||
activityGroupCommunity: "Komunitatea eta gobernantza",
|
||||
activityGroupOrg: "Antolakuntza",
|
||||
activityGroupComm: "Komunikazioa",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
const { a, em, strong } = require('../../../server/node_modules/hyperaxe');
|
||||
module.exports = {
|
||||
fr: {
|
||||
bbAdd: "Ajouter",
|
||||
bbQuickActions: "Actions rapides",
|
||||
bbPickTitle: "Épingler un module",
|
||||
bbPickDesc: "Choisis un module pour l'emplacement + de la barre inférieure.",
|
||||
bbPickNone: "Aucun",
|
||||
activityChangeFilter: "Changer de filtre",
|
||||
emptyConnectHint: "Connecte-toi à un pub pour synchroniser avec le réseau.",
|
||||
emptyConnectCta: "Se connecter à un pub",
|
||||
menuCommunity: "Communauté",
|
||||
activityGroupCommunity: "Communauté et gouvernance",
|
||||
activityGroupOrg: "Organisation",
|
||||
activityGroupComm: "Communication",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
const { a, em, strong } = require('../../../server/node_modules/hyperaxe');
|
||||
module.exports = {
|
||||
hi: {
|
||||
bbAdd: "जोड़ें",
|
||||
bbQuickActions: "त्वरित क्रियाएँ",
|
||||
bbPickTitle: "एक मॉड्यूल पिन करें",
|
||||
bbPickDesc: "नीचे की बार में + स्लॉट के लिए एक मॉड्यूल चुनें।",
|
||||
bbPickNone: "कोई नहीं",
|
||||
activityChangeFilter: "फ़िल्टर बदलें",
|
||||
emptyConnectHint: "नेटवर्क से सिंक करने के लिए किसी pub से जुड़ें।",
|
||||
emptyConnectCta: "pub से जुड़ें",
|
||||
menuCommunity: "समुदाय",
|
||||
activityGroupCommunity: "समुदाय और शासन",
|
||||
activityGroupOrg: "संगठन",
|
||||
activityGroupComm: "संचार",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
const { a, em, strong } = require('../../../server/node_modules/hyperaxe');
|
||||
module.exports = {
|
||||
it: {
|
||||
bbAdd: "Aggiungi",
|
||||
bbQuickActions: "Azioni rapide",
|
||||
bbPickTitle: "Fissa un modulo",
|
||||
bbPickDesc: "Scegli un modulo per lo spazio + nella barra inferiore.",
|
||||
bbPickNone: "Nessuno",
|
||||
activityChangeFilter: "Cambia filtro",
|
||||
emptyConnectHint: "Connettiti a un pub per sincronizzarti con la rete.",
|
||||
emptyConnectCta: "Connettiti a un pub",
|
||||
menuCommunity: "Comunità",
|
||||
activityGroupCommunity: "Comunità e governance",
|
||||
activityGroupOrg: "Organizzazione",
|
||||
activityGroupComm: "Comunicazione",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
const { a, em, strong } = require('../../../server/node_modules/hyperaxe');
|
||||
module.exports = {
|
||||
pt: {
|
||||
bbAdd: "Adicionar",
|
||||
bbQuickActions: "Ações rápidas",
|
||||
bbPickTitle: "Fixar um módulo",
|
||||
bbPickDesc: "Escolhe um módulo para o espaço + da barra inferior.",
|
||||
bbPickNone: "Nenhum",
|
||||
activityChangeFilter: "Mudar filtro",
|
||||
emptyConnectHint: "Liga-te a um pub para sincronizar com a rede.",
|
||||
emptyConnectCta: "Ligar a um pub",
|
||||
menuCommunity: "Comunidade",
|
||||
activityGroupCommunity: "Comunidade e governança",
|
||||
activityGroupOrg: "Organização",
|
||||
activityGroupComm: "Comunicação",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
const { a, em, strong } = require('../../../server/node_modules/hyperaxe');
|
||||
module.exports = {
|
||||
ru: {
|
||||
bbAdd: "Добавить",
|
||||
bbQuickActions: "Быстрые действия",
|
||||
bbPickTitle: "Закрепить модуль",
|
||||
bbPickDesc: "Выберите модуль для слота + в нижней панели.",
|
||||
bbPickNone: "Нет",
|
||||
activityChangeFilter: "Сменить фильтр",
|
||||
emptyConnectHint: "Подключитесь к пабу для синхронизации с сетью.",
|
||||
emptyConnectCta: "Подключиться к пабу",
|
||||
menuCommunity: "Сообщество",
|
||||
activityGroupCommunity: "Сообщество и управление",
|
||||
activityGroupOrg: "Организация",
|
||||
activityGroupComm: "Коммуникация",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
const { a, em, strong } = require('../../../server/node_modules/hyperaxe');
|
||||
module.exports = {
|
||||
zh: {
|
||||
bbAdd: "添加",
|
||||
bbQuickActions: "快捷操作",
|
||||
bbPickTitle: "固定一个模块",
|
||||
bbPickDesc: "为底部栏的 + 位置选择一个模块。",
|
||||
bbPickNone: "无",
|
||||
activityChangeFilter: "更改筛选",
|
||||
emptyConnectHint: "连接到一个 pub 以与网络同步。",
|
||||
emptyConnectCta: "连接到 pub",
|
||||
menuCommunity: "社区",
|
||||
activityGroupCommunity: "社区与治理",
|
||||
activityGroupOrg: "组织",
|
||||
activityGroupComm: "沟通",
|
||||
|
|
|
|||
|
|
@ -112,6 +112,42 @@ const renderContentActions = (msgId, viewHref) => {
|
|||
};
|
||||
exports.renderContentActions = renderContentActions;
|
||||
|
||||
const emptyState = ({ icon, title, text, ctaHref, ctaLabel }) => div(
|
||||
{ class: "empty-state" },
|
||||
icon ? span({ class: "empty-state-icon" }, icon) : "",
|
||||
title ? p({ class: "empty-state-title" }, title) : "",
|
||||
text ? p({ class: "empty-state-text" }, text) : "",
|
||||
(ctaHref && ctaLabel) ? a({ class: "empty-state-cta filter-btn", href: ctaHref }, ctaLabel) : ""
|
||||
);
|
||||
exports.emptyState = emptyState;
|
||||
|
||||
exports.bottomBarPickerView = () => {
|
||||
const cfg = getConfig();
|
||||
const modOn = (m) => !m || cfg.modules[m] === 'on' || cfg.modules[m] === undefined;
|
||||
const current = cfg.bottomBarPin || '';
|
||||
const pick = (key, glyph, labelText) => form({ method: 'POST', action: '/settings/bottombar', class: 'bb-pick-form' },
|
||||
input({ type: 'hidden', name: 'pin', value: key }),
|
||||
button({ type: 'submit', class: current === key ? 'bb-pick-btn active' : 'bb-pick-btn' },
|
||||
span({ class: 'bb-pick-ico' }, glyph),
|
||||
span({ class: 'bb-pick-lbl' }, labelText)
|
||||
)
|
||||
);
|
||||
const items = exports.PINNABLE_MODULES.filter(m => modOn(m.mod)).map(m => pick(m.key, m.glyph, i18n[m.labelKey] || m.key));
|
||||
return template(
|
||||
i18n.bbPickTitle || 'Pin a module',
|
||||
section(
|
||||
div({ class: 'tags-header' },
|
||||
h2(i18n.bbPickTitle || 'Pin a module'),
|
||||
p(i18n.bbPickDesc || 'Choose a module for the + slot in the bottom bar.')
|
||||
),
|
||||
div({ class: 'bb-pick-grid' },
|
||||
pick('', '✕', i18n.bbPickNone || 'None'),
|
||||
...items
|
||||
)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
exports.renderStateChip = renderStateChip;
|
||||
exports.renderOpenClosedChip = renderOpenClosedChip;
|
||||
exports.renderVisibilityChip = renderVisibilityChip;
|
||||
|
|
@ -1080,24 +1116,76 @@ const renderMobileTopbar = () => div(
|
|||
a({ class: "omt-avatar", href: "/profile" }, img({ src: (typeof global !== "undefined" && global.__OASIS_SELF_AVATAR__) || "/assets/images/default-avatar.png", alt: i18n.profile || "Profile" }))
|
||||
);
|
||||
|
||||
const PINNABLE_MODULES = [
|
||||
{ key: 'tribes', href: '/tribes', glyph: 'ꖥ', labelKey: 'tribesTitle', mod: 'tribesMod' },
|
||||
{ key: 'chats', href: '/chats', glyph: 'ꖒ', labelKey: 'chatsTitle', mod: 'chatsMod' },
|
||||
{ key: 'market', href: '/market', glyph: 'ꕻ', labelKey: 'marketTitle', mod: 'marketMod' },
|
||||
{ key: 'events', href: '/events', glyph: 'ꕆ', labelKey: 'eventsLabel', mod: 'eventsMod' },
|
||||
{ key: 'calendars', href: '/calendars', glyph: 'ꖯ', labelKey: 'calendarsTitle', mod: 'calendarsMod' },
|
||||
{ key: 'banking', href: '/banking', glyph: 'ꗴ', labelKey: 'bankingTitle', mod: 'bankingMod' },
|
||||
{ key: 'forum', href: '/forum', glyph: 'ꕒ', labelKey: 'forumTitle', mod: 'forumMod' },
|
||||
{ key: 'videos', href: '/videos', glyph: 'ꗟ', labelKey: 'videosLabel', mod: 'videosMod' },
|
||||
{ key: 'images', href: '/images', glyph: 'ꕥ', labelKey: 'imagesLabel', mod: 'imagesMod' },
|
||||
{ key: 'audios', href: '/audios', glyph: 'ꔿ', labelKey: 'audiosLabel', mod: 'audiosMod' },
|
||||
{ key: 'documents', href: '/documents', glyph: 'ꕨ', labelKey: 'docsLabel', mod: 'docsMod' },
|
||||
{ key: 'bookmarks', href: '/bookmarks', glyph: 'ꔪ', labelKey: 'bookmarksLabel', mod: 'bookmarksMod' },
|
||||
{ key: 'maps', href: '/maps', glyph: 'ꔌ', labelKey: 'mapsLabel', mod: 'mapsMod' },
|
||||
{ key: 'trending', href: '/trending', glyph: 'ꗝ', labelKey: 'trendingLabel', mod: 'trendingMod' },
|
||||
{ key: 'jobs', href: '/jobs', glyph: 'ꗒ', labelKey: 'jobsTitle', mod: 'jobsMod' },
|
||||
{ key: 'agenda', href: '/agenda', glyph: 'ꗤ', labelKey: 'agendaTitle', mod: 'agendaMod' },
|
||||
{ key: 'wallet', href: '/wallet', glyph: '❄', labelKey: 'wallet', mod: 'walletMod' },
|
||||
{ key: 'tasks', href: '/tasks', glyph: 'ꖧ', labelKey: 'tasksTitle', mod: 'tasksMod' },
|
||||
{ key: 'torrents', href: '/torrents', glyph: 'ꖅ', labelKey: 'torrentsLabel', mod: 'torrentsMod' },
|
||||
{ key: 'tags', href: '/tags', glyph: 'ꖶ', labelKey: 'tagsLabel', mod: 'tagsMod' },
|
||||
{ key: 'pads', href: '/pads', glyph: 'ꔗ', labelKey: 'padsTitle', mod: 'padsMod' },
|
||||
{ key: 'projects', href: '/projects', glyph: 'ꕧ', labelKey: 'projectsTitle', mod: 'projectsMod' },
|
||||
{ key: 'shops', href: '/shops', glyph: 'ꔜ', labelKey: 'shopsTitle', mod: 'shopsMod' },
|
||||
{ key: 'transfers', href: '/transfers', glyph: 'ꘉ', labelKey: 'transfersTitle', mod: 'transfersMod' },
|
||||
{ key: 'feed', href: '/feed', glyph: 'ꕿ', labelKey: 'feedTitle', mod: 'feedMod' },
|
||||
{ key: 'pixelia', href: '/pixelia', glyph: 'ꔘ', labelKey: 'pixeliaTitle', mod: 'pixeliaMod' },
|
||||
{ key: 'melody', href: '/melody', glyph: '♪', labelKey: 'melodyTitle', mod: 'melodyMod' },
|
||||
{ key: 'games', href: '/games', glyph: 'ꕇ', labelKey: 'gamesTitle', mod: 'gamesMod' },
|
||||
{ key: 'votes', href: '/votes', glyph: 'ꔰ', labelKey: 'votationsTitle', mod: 'votesMod' },
|
||||
{ key: 'reports', href: '/reports', glyph: 'ꕥ', labelKey: 'reportsTitle', mod: 'reportsMod' },
|
||||
{ key: 'opinions', href: '/opinions', glyph: 'ꔍ', labelKey: 'opinionsTitle', mod: 'opinionsMod' },
|
||||
{ key: 'parliament',href: '/parliament',glyph: 'ꗞ', labelKey: 'parliamentTitle',mod: 'parliamentMod' },
|
||||
{ key: 'courts', href: '/courts', glyph: 'ꖻ', labelKey: 'courtsTitle', mod: 'courtsMod' },
|
||||
{ key: 'larp', href: '/larp', glyph: '✦', labelKey: 'larpTitle', mod: 'larpMod' },
|
||||
{ key: 'ai', href: '/ai', glyph: 'ꘜ', labelKey: 'ai', mod: 'aiMod' },
|
||||
{ key: 'cipher', href: '/cipher', glyph: 'ꗄ', labelKey: 'cipher', mod: 'cipherMod' },
|
||||
{ key: 'fediverse', href: '/fediverse', glyph: 'ꗵ', labelKey: 'fediverseTimeline', mod: 'fediverseMod' },
|
||||
{ key: 'inhabitants', href: '/inhabitants', glyph: 'ꖘ', labelKey: 'inhabitantsLabel', mod: null },
|
||||
{ key: 'cv', href: '/cv', glyph: 'ꕛ', labelKey: 'cvTitle', mod: null },
|
||||
{ key: 'stats', href: '/stats', glyph: 'ꕷ', labelKey: 'statistics', mod: null },
|
||||
{ key: 'blockexplorer', href: '/blockexplorer', glyph: 'ꖸ', labelKey: 'blockchain', mod: null },
|
||||
];
|
||||
exports.PINNABLE_MODULES = PINNABLE_MODULES;
|
||||
|
||||
const renderBottomBar = () => {
|
||||
const inboxN = sharedState.getInboxCount();
|
||||
const cfg = getConfig();
|
||||
const modOn = (m) => !m || cfg.modules[m] === 'on' || cfg.modules[m] === undefined;
|
||||
const bbLink = (href, ico, label, badge) => a(
|
||||
{ class: "bb-item", href },
|
||||
span({ class: "bb-ico" }, ico),
|
||||
(badge && badge > 0) ? span({ class: "bb-badge" }, String(badge)) : "",
|
||||
span({ class: "bb-lbl" }, label)
|
||||
);
|
||||
const pinned = PINNABLE_MODULES.find(m => m.key === (cfg.bottomBarPin || '') && modOn(m.mod));
|
||||
const pinSlot = pinned
|
||||
? bbLink(pinned.href, pinned.glyph, i18n[pinned.labelKey] || pinned.key)
|
||||
: a({ class: "bb-item bb-add", href: "/settings/bottombar" },
|
||||
span({ class: "bb-ico" }, "+"),
|
||||
span({ class: "bb-lbl" }, i18n.bbAdd || "Add"));
|
||||
const pair = [ bbLink("/peers", "⧖", i18n.peers || "Peers") ];
|
||||
if (modOn('invitesMod')) pair.push(bbLink("/invites", "ꔮ", i18n.invites || "Invites"));
|
||||
return nav(
|
||||
{ class: "oasis-bottombar", style: "display:none", "aria-label": "Quick actions" },
|
||||
bbLink("/search", "ꔅ", i18n.searchTitle || "Buscar"),
|
||||
bbLink("/inbox", "☂", i18n.inbox || "Inbox", inboxN),
|
||||
bbLink("/publish", "❂", i18n.publish || "Write"),
|
||||
bbLink("/activity", "ꔙ", i18n.activityTitle || "Activity"),
|
||||
div({ class: "bb-pair" },
|
||||
bbLink("/peers", "⧖", i18n.peers || "Peers"),
|
||||
bbLink("/invites", "ꔮ", i18n.invites || "Invites")
|
||||
)
|
||||
{ class: "oasis-bottombar", style: "display:none", "aria-label": i18n.bbQuickActions || "Quick actions" },
|
||||
bbLink("/search", "ꔅ", i18n.searchTitle || "Search"),
|
||||
bbLink("/inbox", "☂", i18n.inbox || "Inbox", inboxN),
|
||||
bbLink("/publish", "❂", i18n.publish || "Write"),
|
||||
pinSlot,
|
||||
div({ class: "bb-pair" }, ...pair)
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -3402,7 +3490,7 @@ exports.privateView = async (messagesInput, filter, decrypted = null) => {
|
|||
threadGroups[tid].push(msg)
|
||||
}
|
||||
|
||||
if (!threadOrder.length) return p({ class: 'empty' }, i18n.noPrivateMessages)
|
||||
if (!threadOrder.length) return emptyState({ icon: "✉", title: i18n.noPrivateMessages, text: i18n.emptyConnectHint, ctaHref: "/invites", ctaLabel: i18n.emptyConnectCta })
|
||||
|
||||
return threadOrder.map(tid => {
|
||||
const msgs = threadGroups[tid]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue