[0.9.1] Mobile usability: filter hexagons by tab, collapse activity filters

- Personal/Community/All header tabs now filter the home hexagon nav (default
  All shows the 10; Personal/Community show their 5) via the CSS radio-hack.
  Removed the square-accordion sidebars (.sidebar-left/.sidebar-right) they
  replaced.
- Wrap the dense activity filter strip (RECENT/ALL/MINE/…) in a collapsible
  FILTER dropdown, hidden by default, keeping the hexagons visible above.
- Add the missing English i18n keys (menuCommunity, menuAll, filter, bb*).
This commit is contained in:
s1to 2026-08-04 11:07:48 +02:00
parent 871cccbe17
commit c088d176c1
4 changed files with 79 additions and 218 deletions

View file

@ -1,4 +1,4 @@
const { div, h2, p, section, button, form, a, input, img, textarea, br, span, video: videoHyperaxe, audio: audioHyperaxe, table, tr, td, th, details, summary } = require("../server/node_modules/hyperaxe");
const { div, h2, p, section, button, form, a, input, label, img, textarea, br, span, video: videoHyperaxe, audio: audioHyperaxe, table, tr, td, th, details, summary } = require("../server/node_modules/hyperaxe");
const { template, i18n, userLink, userLinkLabel, renderSpreadButton, renderContentActions, renderHiveNav } = require('./main_views');
const opinionCategories = require('../backend/opinion_categories');
@ -1994,30 +1994,35 @@ exports.activityView = (actions, filter, userId, q = '', extras = {}) => {
p(desc)
),
renderHiveNav(),
div({ class: 'activity-filter-grid' },
...[
activityTypes.slice(0, 3),
activityTypes.slice(3, 8),
activityTypes.slice(8, 13),
activityTypes.slice(13, 19),
activityTypes.slice(19, 26),
activityTypes.slice(26)
].map(col =>
div({ class: 'activity-filter-col' },
col.map(({ type, label }) =>
form({ method: 'GET', action: '/activity' },
input({ type: 'hidden', name: 'filter', value: type }),
button({ type: 'submit', class: filter === type ? 'filter-btn active' : 'filter-btn' }, label)
input({ type: 'checkbox', id: 'activity-filter-toggle', class: 'hive-filter-radio' }),
label({ for: 'activity-filter-toggle', class: 'activity-filter-btn' },
span(i18n.filter || 'Filter'), span({ class: 'activity-filter-caret' }, '▾')),
div({ class: 'activity-filter-panel' },
div({ class: 'activity-filter-grid' },
...[
activityTypes.slice(0, 3),
activityTypes.slice(3, 8),
activityTypes.slice(8, 13),
activityTypes.slice(13, 19),
activityTypes.slice(19, 26),
activityTypes.slice(26)
].map(col =>
div({ class: 'activity-filter-col' },
col.map(({ type, label }) =>
form({ method: 'GET', action: '/activity' },
input({ type: 'hidden', name: 'filter', value: type }),
button({ type: 'submit', class: filter === type ? 'filter-btn active' : 'filter-btn' }, label)
)
)
)
)
)
),
sub
? div({ class: 'activity-sub-filter' },
sub.filters.map(f => a({ href: `${sub.url}?filter=${encodeURIComponent(f)}`, class: 'filter-btn' }, String(f).toUpperCase()))
)
: null
),
sub
? div({ class: 'activity-sub-filter' },
sub.filters.map(f => a({ href: `${sub.url}?filter=${encodeURIComponent(f)}`, class: 'filter-btn' }, String(f).toUpperCase()))
)
: null,
section({ class: 'feed-container' }, renderActionCards(filteredActions, userId, actions, spreadMap))
)
);

View file

@ -1239,7 +1239,8 @@ const renderHiveNav = () => {
{ id: 'fediverse', emoji: '⌬', title: i18n.fediverse, mods: [
{ href: '/fediverse', glyph: 'ꗵ', labelKey: 'fediverseTimeline', mod: 'fediverseMod' } ] },
];
const catHex = (c) => label({ for: `hive-${c.id}`, class: 'hex-cat' },
const half = (c) => (CATS.indexOf(c) < 5 ? 'hive-half-p' : 'hive-half-c');
const catHex = (c) => label({ for: `hive-${c.id}`, class: `hex-cat ${half(c)}` },
span({ class: 'hx-ico' }, c.emoji), span({ class: 'hx-lbl' }, c.title));
const modHex = (m) => a({ class: 'hex-mod', href: m.href },
span({ class: 'hx-ico' }, m.glyph), span({ class: 'hx-lbl' }, i18n[m.labelKey] || ''));
@ -1248,7 +1249,7 @@ const renderHiveNav = () => {
let idx = 0;
for (const size of [3, 4, 3]) { catRows.push(div({ class: 'hive-row' }, ...CATS.slice(idx, idx + size).map(catHex))); idx += size; }
const grid = div({ class: 'hive-grid hive-cats' }, ...catRows);
const panels = CATS.map(c => div({ class: 'hive-panel', id: `hive-panel-${c.id}` },
const panels = CATS.map(c => div({ class: `hive-panel ${half(c)}`, id: `hive-panel-${c.id}` },
div({ class: 'hive-mods' }, ...c.mods.filter(m => modOn(m.mod)).map(modHex))
));
return div({ class: 'hive-nav' }, ...radios, grid, ...panels);
@ -1284,17 +1285,17 @@ const template = (titlePrefix, ...elements) => {
})
),
body(
input({ type: "checkbox", id: "nav-left-toggle", class: "oasis-nav-side-toggle" }),
input({ type: "checkbox", id: "nav-right-toggle", class: "oasis-nav-side-toggle" }),
input({ type: "radio", name: "hive-filter", id: "hive-filter-all", class: "hive-filter-radio", checked: true }),
input({ type: "radio", name: "hive-filter", id: "hive-filter-personal", class: "hive-filter-radio" }),
input({ type: "radio", name: "hive-filter", id: "hive-filter-community", class: "hive-filter-radio" }),
div(
{ class: uxMode === "ainav" ? "header ainav-only" : "header" },
renderMobileTopbar(),
div(
{ class: "oasis-mobile-menus" },
label({ for: "nav-left-toggle", class: "oasis-menu-btn" },
span({ class: "oasis-menu-ico" }, "☰"), span(i18n.menuPersonal || "Personal")),
label({ for: "nav-right-toggle", class: "oasis-menu-btn" },
span({ class: "oasis-menu-ico" }, "☰"), span(i18n.menuCommunity || "Community"))
label({ for: "hive-filter-all", class: "oasis-menu-btn" }, span(i18n.menuAll || "All")),
label({ for: "hive-filter-personal", class: "oasis-menu-btn" }, span(i18n.menuPersonal || "Personal")),
label({ for: "hive-filter-community", class: "oasis-menu-btn" }, span(i18n.menuCommunity || "Community"))
),
(() => {
const aiNavOn = getConfig().modules.aiNavMod === 'on';
@ -1349,185 +1350,7 @@ const template = (titlePrefix, ...elements) => {
})(),
div(
{ class: uxMode === "ainav" ? "main-content ainav-only" : "main-content" },
uxMode === "ainav" ? null : div(
{ class: "sidebar-left" },
nav(
ul(
navGroup(
{
id: "personal",
emoji: "⚉",
title: i18n.menuPersonal
},
navLink({
href: "/profile",
emoji: "⚉",
text: i18n.profile
}),
navLink({
href: "/cv",
emoji: "ꕛ",
text: i18n.cvTitle
}),
renderAgendaLink(),
renderFavoritesLink(),
renderLogsLink(),
renderWalletLink(),
navLink({
href: "/modules",
emoji: "ꗣ",
text: i18n.modules
}),
navLink({
href: "/settings",
emoji: "⚙",
text: i18n.settings
})
),
navGroup(
{
id: "governance",
emoji: "⚖",
title: i18n.menuGovernance
},
navLink({
href: "/inhabitants",
emoji: "ꖘ",
text: i18n.inhabitantsLabel
}),
renderTribesLink(),
renderLarpLink(),
renderParliamentLink(),
renderCourtsLink()
),
navGroup(
{
id: "office",
emoji: "⌂",
title: i18n.menuOffice
},
renderVotationsLink(),
renderEventsLink(),
renderCalendarsLink(),
renderTasksLink(),
renderReportsLink()
),
navGroup(
{
id: "economy",
emoji: "¤",
title: i18n.menuEconomy
},
renderBankingLink(),
renderMarketLink(),
renderProjectsLink(),
renderIndustryLink(),
renderJobsLink(),
renderShopsLink(),
renderTransfersLink()
),
navGroup(
{
id: "tools",
emoji: "⚒",
title: i18n.menuTools
},
renderAILink(),
navLink({
href: "/blockexplorer",
emoji: "ꖸ",
text: i18n.blockchain
}),
renderDevLink(),
renderCipherLink(),
renderInvitesLink(),
renderLegacyLink(),
navLink({
href: "/stats",
emoji: "ꕷ",
text: i18n.statistics
})
)
)
)
),
main({ id: "content", class: "main-column" }, elements),
uxMode === "ainav" ? null : div(
{ class: "sidebar-right" },
nav(
ul(
navGroup(
{
id: "network",
emoji: "☍",
title: i18n.menuNetwork
},
navLink({
href: "/activity",
emoji: "ꔙ",
text: i18n.activityTitle
}),
renderTagsLink(),
renderTrendingLink(),
renderOpinionsLink(),
renderPadsLink(),
renderForumLink(),
renderMapsLink(),
renderChatsLink()
),
navGroup(
{
id: "blogs",
emoji: "✦",
title: i18n.menuBlogs
},
navLink({
href: "/mentions",
emoji: "✺",
text: i18n.mentions
}),
renderLatestLink(),
renderThreadsLink(),
renderTopicsLink(),
renderSummariesLink(),
renderPopularLink(),
renderMultiverseLink()
),
navGroup(
{
id: "creative",
emoji: "✎",
title: i18n.menuCreative
},
renderFeedLink(),
renderGamesLink(),
renderPixeliaLink(),
renderMelodyLink()
),
navGroup(
{
id: "media",
emoji: "▤",
title: i18n.menuMedia
},
renderAudiosLink(),
renderBookmarksLink(),
renderDocsLink(),
renderImagesLink(),
renderTorrentsLink(),
renderVideosLink()
),
navGroup(
{
id: "fediverse",
emoji: "⌬",
title: i18n.fediverse
},
renderMastodonLink()
)
)
)
)
main({ id: "content", class: "main-column" }, elements)
),
renderBottomBar(),
renderFooter()