The phone mode improvements for the forums subscribed post/detail view have been implemented

- matching the design patterns established in boards and channels.
This commit is contained in:
defnax 2026-09-11 16:58:03 +02:00
parent 8c397b65ee
commit 2bb09c4bcf
5 changed files with 453 additions and 144 deletions

View File

@ -534,7 +534,7 @@ const ThreadView = () => {
if (!threadStruct) {
return m('.forum-thread-view', [
m(
'a[title=Back]',
'a.forum-back[title=Back][aria-label=Back]',
{
onclick: () => m.route.set('/forums/:tab/:mGroupId', {
tab: m.route.param().tab,
@ -552,7 +552,7 @@ const ThreadView = () => {
return m('.forum-thread-view', { key: msgId }, [
m(
'a[title=Back]',
'a.forum-back[title=Back][aria-label=Back]',
{
onclick: () => m.route.set('/forums/:tab/:mGroupId', {
tab: m.route.param().tab,
@ -611,6 +611,7 @@ const ThreadView = () => {
const ForumView = () => {
let ownId = '';
let threadSearch = '';
return {
oninit: (v) => {
util.updatedisplayforums(v.attrs.id);
@ -649,46 +650,108 @@ const ForumView = () => {
fauthor = rs.userList.username(forumDetails.author);
}
const toggleSubscription = async () => {
const res = await rs.rsJsonApiRequest('/rsgxsforums/subscribeToForum', {
forumId: v.attrs.id,
subscribe: !fsubscribed,
});
if (res.body.retval) {
util.Data.DisplayForums[v.attrs.id].isSubscribed = !fsubscribed;
if (v.attrs.onSubscriptionChange) await v.attrs.onSubscriptionChange();
m.redraw();
}
};
const query = threadSearch.trim().toLowerCase();
const filteredPosts = query
? allPosts.filter((thread) => (thread.mMsgName || '').toLowerCase().includes(query))
: allPosts;
return [
m(
'a[title=Back]',
{
onclick: () =>
m.route.set('/forums/:tab', {
tab: m.route.param().tab,
}),
},
m('i.fas.fa-arrow-left')
),
m('.forum-detail-navigation', [
m(
'a.forum-back[title=Back][aria-label=Back]',
{
onclick: () =>
m.route.set('/forums/:tab', {
tab: m.route.param().tab || 'Subscribed',
}),
},
m('i.fas.fa-arrow-left')
),
m('.forum-mobile-search', [
m('input[type=search][placeholder=Search threads...]', {
value: threadSearch,
oninput: (e) => {
threadSearch = e.target.value;
},
}),
]),
m('details.forum-mobile-actions', {
onkeydown: (event) => {
if (event.key === 'Escape') {
event.currentTarget.open = false;
event.currentTarget.querySelector('summary').focus();
}
},
onfocusout: (event) => {
if (!event.currentTarget.contains(event.relatedTarget)) event.currentTarget.open = false;
},
}, [
m('summary[aria-label=Forum actions][title=Forum actions]', m('i.fas.fa-ellipsis-v')),
m('.forum-mobile-actions__items', m('button[type=button]', {
onclick: (event) => {
const menu = event.currentTarget.closest('details');
menu.open = false;
menu.querySelector('summary').focus();
return toggleSubscription();
},
}, fsubscribed ? 'Unsubscribe' : 'Subscribe')),
]),
]),
m('.widget__heading.forum-detail-heading', [
m('h3', fname),
m(
'button',
fsubscribed && m(
'button.forum-mobile-create[type=button][title=New Thread][aria-label=New Thread]',
{
onclick: async () => {
const res = await rs.rsJsonApiRequest('/rsgxsforums/subscribeToForum', {
forumId: v.attrs.id,
subscribe: !fsubscribed,
});
if (res.body.retval) {
util.Data.DisplayForums[v.attrs.id].isSubscribed = !fsubscribed;
}
onclick: () => {
util.popupmessage(
m(AddThread, {
parent_thread: '',
forumId: v.attrs.id,
authorId: ownId,
parentId: '',
}),
'create-forum-thread-modal'
);
},
},
m('i.fas.fa-pencil-alt')
),
m(
'button.forum-subscription-button',
{
class: fsubscribed ? 'forum-subscription--subscribed' : '',
onclick: toggleSubscription,
},
fsubscribed ? 'Subscribed' : 'Subscribe'
),
]),
m('.forum-detail-card', [
m('.forum-detail-card__icon[role=img][aria-label=Forum]',
m('i.fas.fa-bullhorn')
),
m('.forum-detail-card__details', [
m('div', [m('b', 'Date created: '), m('span', formatTimestamp(createDate))]),
m('div', [m('b', 'Admin: '), m('span', fauthor)]),
m('div', [m('b', 'Last activity: '), m('span', formatTimestamp(lastActivity))]),
m('.media-item', [
m('.media-item__details', [
m(
'.forum-detail-default-thumbnail[role=img][aria-label=Default forum thumbnail]',
m('i.fas.fa-bullhorn')
),
m('.media-item__details-info', [
m('div', [m('b', 'Threads: '), m('span', allPosts.length)]),
m('div', [m('b', 'Date created: '), m('span', formatTimestamp(createDate))]),
m('div', [m('b', 'Admin: '), m('span', fauthor)]),
m('div', [m('b', 'Last activity: '), m('span', formatTimestamp(lastActivity))]),
]),
]),
m('.forum-detail-card__description', [
m('.media-item__desc', [
m('b', 'Description: '),
m('span', forumDetails.description || 'No Description'),
]),
@ -722,21 +785,18 @@ const ForumView = () => {
util.ThreadsTable,
m(
'tbody',
allPosts
.sort((a, b) => getTimestampValue(b.mPublishTs) - getTimestampValue(a.mPublishTs))
.map((thread) =>
m(
'tr',
{
style:
thread.mMsgStatus === util.THREAD_UNREAD ? { fontWeight: 'bold' } : '',
},
m('td', { style: { padding: '10px 0' } }, [
m('div.date', { style: { fontSize: '0.8em', color: '#888' } },
formatTimestamp(thread.mPublishTs)
),
m('div.title', {
style: { fontWeight: 'bold', fontSize: '1.2em', cursor: 'pointer', margin: '5px 0' },
filteredPosts.length === 0
? m('tr', m('td.forum-threads__empty', {
style: { textAlign: 'center', padding: '1.25rem', color: '#64748b', fontSize: '.9rem' },
}, query ? 'No threads matching search.' : 'No threads in this forum yet.'))
: filteredPosts
.sort((a, b) => getTimestampValue(b.mPublishTs) - getTimestampValue(a.mPublishTs))
.map((thread) =>
m(
'tr.forum-thread-row',
{
class:
thread.mMsgStatus === util.THREAD_UNREAD ? 'forum-thread-row--unread' : '',
onclick: () => {
m.route.set('/forums/:tab/:mGroupId/:mMsgId', {
tab: m.route.param().tab,
@ -744,11 +804,17 @@ const ForumView = () => {
mMsgId: thread.mOrigMsgId,
});
},
}, thread.mMsgName),
m('div.author', { style: { fontSize: '0.9em', fontStyle: 'italic' } }, rs.userList.username(thread.mAuthorId)),
])
},
m('td.forum-thread-row__cell', [
m('.forum-thread-row__title', thread.mMsgName),
m('.forum-thread-row__meta', [
m('span.forum-thread-row__author', rs.userList.username(thread.mAuthorId)),
m('span.forum-thread-row__bullet', '•'),
m('span.forum-thread-row__date', formatTimestamp(thread.mPublishTs)),
]),
])
)
)
)
)
)
),

View File

@ -38,6 +38,15 @@ const sections = {
const Layout = () => {
let ownId;
const createForum = () =>
ownId &&
util.popupmessage(
m(viewUtil.createforum, {
authorId: ownId,
onCreated: getForums.load,
}),
'create-forum-modal'
);
return {
oninit: () => {
@ -57,22 +66,18 @@ const Layout = () => {
ownId.unshift(0);
});
},
view: (vnode) =>
m('.widget', [
view: (vnode) => {
const isForumDetail = vnode.attrs.pathInfo.mGroupId && !vnode.attrs.pathInfo.mMsgId;
const isThreadDetail = vnode.attrs.pathInfo.mGroupId && vnode.attrs.pathInfo.mMsgId;
return m('.widget', {
class: isForumDetail ? 'forums-detail-widget' : isThreadDetail ? 'forums-thread-widget' : '',
}, [
m('.top-heading', [
vnode.attrs.pathInfo.tab === 'MyForums' &&
m(
'button',
'button.forums-create-button',
{
onclick: () =>
ownId &&
util.popupmessage(
m(viewUtil.createforum, {
authorId: ownId,
onCreated: getForums.load,
}),
'create-forum-modal'
),
onclick: createForum,
},
'Create Forum'
),
@ -88,11 +93,14 @@ const Layout = () => {
: Object.prototype.hasOwnProperty.call(vnode.attrs.pathInfo, 'mGroupId') // Forum's view
? m(viewUtil.ForumView, {
id: vnode.attrs.pathInfo.mGroupId,
onSubscriptionChange: getForums.load,
})
: m(sections[vnode.attrs.pathInfo.tab], {
list: getForums[vnode.attrs.pathInfo.tab],
onCreateForum: createForum,
}),
]),
]);
},
};
};

View File

@ -4,7 +4,12 @@ const util = require('forums/forums_util');
const Layout = () => {
return {
view: (v) => [
m('.widget__heading', m('h3', 'My Forums')),
m('.widget__heading', [
m('h3', 'My Forums'),
m('button.forums-heading-create[type=button][title=Create Forum][aria-label=Create Forum]', {
onclick: v.attrs.onCreateForum,
}, m('i.fas.fa-plus')),
]),
m('.widget__body', [
m(
util.ForumTable,

View File

@ -70,57 +70,38 @@ table.forums tr.hidden {
padding: 10px;
}
.forum-detail-navigation {
display: flex;
align-items: center;
}
.forum-mobile-search,
.forum-mobile-actions,
.forum-mobile-create,
.forums-heading-create {
display: none;
}
.forum-detail-heading {
margin-top: .75rem;
h3 { margin: 0; }
}
.forum-detail-card {
display: grid;
grid-template-columns: 6rem minmax(15rem, 2fr) minmax(18rem, 3fr);
grid-template-areas: 'icon details description';
.forum-detail-default-thumbnail {
display: flex;
flex: 0 0 6rem;
align-items: center;
gap: 1rem 2rem;
margin-top: .75rem;
padding: 1rem;
border: 1px solid #d7dee8;
justify-content: center;
width: 6rem;
height: 6rem;
border: 1px solid #cbd5e1;
border-radius: 4px;
background: #fff;
background: linear-gradient(135deg, #eef6fb, #dbeafe);
color: #3ba4d7;
box-sizing: border-box;
&__icon {
grid-area: icon;
display: flex;
align-items: center;
justify-content: center;
width: 6rem;
height: 6rem;
border: 1px solid #cbd5e1;
border-radius: 4px;
background: linear-gradient(135deg, #eef6fb, #dbeafe);
color: #3ba4d7;
box-sizing: border-box;
}
&__icon i { font-size: 2.75rem; }
&__details {
grid-area: details;
display: flex;
flex-direction: column;
gap: .3rem;
}
&__description { grid-area: description; }
&__details > div,
&__description {
min-width: 0;
overflow-wrap: anywhere;
}
&__details b,
&__description b { margin-right: .25rem; }
i { font-size: 2.75rem; }
}
.forum-threads {
@ -144,38 +125,6 @@ table.forums tr.hidden {
}
}
@media (max-width: 700px) {
.forum-detail-heading { align-items: center; gap: .75rem; }
.forum-detail-heading h3 {
min-width: 0;
overflow-wrap: anywhere;
}
.forum-detail-card {
grid-template-columns: 5rem minmax(0, 1fr);
grid-template-areas:
'icon details'
'description description';
align-items: start;
gap: 1rem;
}
.forum-detail-card__icon {
width: 5rem;
height: 5rem;
}
.forum-detail-card__icon i { font-size: 2.25rem; }
.forum-threads__create {
min-width: 2.25rem;
justify-content: center;
padding-inline: .55rem;
}
.forum-threads__create span { display: none; }
}
.p {
margin: 0;
}
@ -184,12 +133,293 @@ table.forums tr.hidden {
background: gray;
}
table.threads tr:hover {
background-color: #eef3f6;
cursor: pointer;
table.threads {
width: 100%;
border-collapse: collapse;
tr.forum-thread-row {
border-bottom: 1px solid #f1f5f9;
cursor: pointer;
transition: background-color .15s ease;
&:hover {
background-color: #f8fafc;
}
&.forum-thread-row--unread {
background-color: #f0f9ff;
.forum-thread-row__title {
font-weight: 700;
color: #0369a1;
}
}
}
.forum-thread-row__cell {
padding: .65rem .5rem;
text-align: left !important;
}
.forum-thread-row__title {
font-size: 1.05rem;
font-weight: 600;
color: #1e293b;
margin-bottom: .25rem;
word-break: break-word;
line-height: 1.3;
}
.forum-thread-row__meta {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: .35rem;
font-size: .82rem;
color: #64748b;
}
.forum-thread-row__author {
font-style: normal;
color: #475569;
font-weight: 500;
}
.forum-thread-row__bullet {
color: #cbd5e1;
font-size: .75rem;
}
.forum-thread-row__date {
color: #94a3b8;
}
td {
word-wrap: break-word;
}
}
table.threads td {
word-wrap: break-word;
@media (max-width: 700px) {
.tab-content:has(.forums-detail-widget),
.tab-content:has(.forums-thread-widget) {
position: relative;
}
.widget.forums-detail-widget {
display: flex;
flex-direction: column;
row-gap: 4px;
> .top-heading {
display: none;
}
.forum-subscription--subscribed,
.forum-threads > .forum-threads__heading {
display: none;
}
.forum-threads {
margin-top: 6px;
min-height: 0;
}
}
.widget.forums-thread-widget {
> .top-heading {
display: none;
}
}
.forum-detail-navigation {
justify-content: space-between;
gap: .5rem;
}
a.forum-back[title='Back'] {
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
padding: 0;
flex-shrink: 0;
border-radius: 50%;
background: #e8f4fc;
color: #0788cb;
font-size: 1.15rem;
text-decoration: none;
cursor: pointer;
&:hover {
background: #d5ebfa;
}
.fa-arrow-left::before {
content: "\f053";
}
}
.forum-mobile-search {
display: flex;
align-items: center;
min-width: 0;
flex: 1;
margin-right: 44px;
input {
min-width: 0;
width: 100%;
height: 36px;
padding: 0 .75rem;
border: 1px solid #cbd5e1;
border-radius: .375rem;
font-size: .85rem;
background: #fff;
box-sizing: border-box;
&:focus {
border-color: #0788cb;
outline: none;
}
}
}
.forum-mobile-create {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
padding: 0;
font-size: .85rem;
border-radius: .375rem;
border: 0;
background: #0788cb;
color: #fff;
cursor: pointer;
&:hover {
background: #0672aa;
}
}
.forum-mobile-actions {
display: block;
position: absolute;
top: 0;
right: .5rem;
z-index: 1001;
summary {
display: flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
cursor: pointer;
list-style: none;
}
summary::-webkit-details-marker {
display: none;
}
summary:focus-visible {
outline: 2px solid #0788cb;
}
&__items {
position: absolute;
right: 0;
top: 100%;
min-width: 10rem;
padding: .35rem;
background: #fff;
border: 1px solid #cbd5e1;
border-radius: .375rem;
box-shadow: 0 4px 12px rgba(15, 23, 42, .15);
}
&__items button {
width: 100%;
min-height: 44px;
text-align: left;
background: #fff;
color: #334155;
box-shadow: none;
border: 0;
padding: 0 .75rem;
border-radius: .25rem;
cursor: pointer;
}
&__items button:hover {
background: #f1f5f9;
}
}
.forum-detail-heading {
display: flex;
align-items: center;
justify-content: space-between;
gap: .5rem;
margin-top: .25rem;
margin-bottom: .25rem;
padding-bottom: .25rem;
border-bottom: 1px solid #e2e8f0;
h3 {
font-size: 1.2rem;
margin: 0;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
table.threads {
.forum-thread-row__cell {
padding: .4rem .25rem;
text-align: left !important;
}
.forum-thread-row__title {
font-size: .92rem;
margin-bottom: .15rem;
}
.forum-thread-row__meta {
font-size: .76rem;
gap: .25rem;
}
}
#searchforum {
margin-left: 0;
width: 100%;
}
.forums-create-button {
display: none;
}
.forums-heading-create {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
padding: 0;
font-size: .85rem;
border-radius: .375rem;
border: 0;
background: #0788cb;
color: #fff;
cursor: pointer;
}
}
table.threadreply th:nth-child(2) {
width: 50%;

File diff suppressed because one or more lines are too long