adding different layouts for testing
This commit is contained in:
@@ -136,8 +136,12 @@
|
||||
"ui_section": "Benutzeroberfläche",
|
||||
"appearance_section": "Erscheinungsbild",
|
||||
"show_motd": "Nachricht des Tages (MOTD) anzeigen",
|
||||
"modern_layout": "Modernes Layout",
|
||||
"modern_layout_hint": "3-Spalten-Layout",
|
||||
"feed_layout": "Feed-Layout",
|
||||
"feed_layout_hint": "Wähle, wie die Hauptseite Beiträge anzeigt",
|
||||
"feed_layout_grid": "Raster (Kompakt)",
|
||||
"feed_layout_modern": "Raster (3-spaltig Modern)",
|
||||
"feed_layout_feed": "Feed (X / Instagram-Stil)",
|
||||
"feed_layout_youtube": "YouTube-Stil",
|
||||
"alternative_infobox": "Alternativer Autor-Infoblock",
|
||||
"alternative_infobox_hint": "Zeigt einen erweiterten Autor-Block mit Avatar und Bio auf Beitragsseiten",
|
||||
"disable_autoplay": "Automatische Wiedergabe deaktivieren",
|
||||
|
||||
@@ -136,8 +136,12 @@
|
||||
"ui_section": "User Interface",
|
||||
"appearance_section": "Appearance",
|
||||
"show_motd": "Show Message of the Day (MOTD)",
|
||||
"modern_layout": "Modern layout",
|
||||
"modern_layout_hint": "3 Column Layout",
|
||||
"feed_layout": "Feed Layout",
|
||||
"feed_layout_hint": "Choose how the main page displays posts",
|
||||
"feed_layout_grid": "Grid (Compact)",
|
||||
"feed_layout_modern": "Grid (3-column Modern)",
|
||||
"feed_layout_feed": "Feed (X / Instagram style)",
|
||||
"feed_layout_youtube": "YouTube Style",
|
||||
"alternative_infobox": "Alternative Author Infobox",
|
||||
"alternative_infobox_hint": "Show a rich author card with avatar and bio on item pages",
|
||||
"disable_autoplay": "Disable Autoplay",
|
||||
|
||||
@@ -136,8 +136,12 @@
|
||||
"ui_section": "Gebruikersinterface",
|
||||
"appearance_section": "Uiterlijk",
|
||||
"show_motd": "Toon Bericht van de Dag (MOTD)",
|
||||
"modern_layout": "Moderne layout",
|
||||
"modern_layout_hint": "Indeling met 3 kolommen",
|
||||
"feed_layout": "Feed-indeling",
|
||||
"feed_layout_hint": "Kies hoe de hoofdpagina berichten weergeeft",
|
||||
"feed_layout_grid": "Raster (Compact)",
|
||||
"feed_layout_modern": "Raster (3-koloms Modern)",
|
||||
"feed_layout_feed": "Feed (X / Instagram-stijl)",
|
||||
"feed_layout_youtube": "YouTube-stijl",
|
||||
"alternative_infobox": "Alternatief auteur-informatievak",
|
||||
"alternative_infobox_hint": "Toont een uitgebreide auteurkaart met avatar en bio op itempagina's",
|
||||
"disable_autoplay": "Automatisch afspelen uitschakelen",
|
||||
|
||||
@@ -136,8 +136,12 @@
|
||||
"ui_section": "Benutzeroberfläche",
|
||||
"appearance_section": "Erscheinungsbild",
|
||||
"show_motd": "Nachricht des Tages (NdT) anzeigen",
|
||||
"modern_layout": "Modernes Layout",
|
||||
"modern_layout_hint": "3-Spalten-Layout",
|
||||
"feed_layout": "Feed-Layout",
|
||||
"feed_layout_hint": "Wählze, wie die Hauptzeite Beiträge anzeigt",
|
||||
"feed_layout_grid": "Raster (Kompakt)",
|
||||
"feed_layout_modern": "Raster (3-spaltig Modern)",
|
||||
"feed_layout_feed": "Feed (X / Instagram-Stil)",
|
||||
"feed_layout_youtube": "YouTube-Stil",
|
||||
"alternative_infobox": "Alternativer Autor-Infoblock",
|
||||
"alternative_infobox_hint": "Zeigt einen erweiterten Autor-Block mit Avatar und Bio auf Beitragsseiten",
|
||||
"disable_autoplay": "Automatische Wiedergabe deaktivieren",
|
||||
|
||||
@@ -12,7 +12,7 @@ import cfg from "../config.mjs";
|
||||
import security from "../security.mjs";
|
||||
import crypto from "crypto";
|
||||
import path from "path";
|
||||
import { getManualApproval, setManualApproval, getMinTags, setMinTags, getRegistrationOpen, setRegistrationOpen, getTrustedUploads, setTrustedUploads, getEnablePdf, setEnablePdf, getLogUserIps, setLogUserIps, getHashUserIps, setHashUserIps, getEnableCleanup, setEnableCleanup, getCleanupStartDate, setCleanupStartDate, getCleanupEndDate, setCleanupEndDate, getShitpostMode } from "../settings.mjs";
|
||||
import { getManualApproval, setManualApproval, getMinTags, setMinTags, getRegistrationOpen, setRegistrationOpen, getTrustedUploads, setTrustedUploads, getEnablePdf, setEnablePdf, getLogUserIps, setLogUserIps, getHashUserIps, setHashUserIps, getEnableCleanup, setEnableCleanup, getCleanupStartDate, setCleanupStartDate, getCleanupEndDate, setCleanupEndDate, getShitpostMode, getDefaultFeedLayout, setDefaultFeedLayout } from "../settings.mjs";
|
||||
|
||||
export default (router, tpl) => {
|
||||
router.get(/^\/login(\/)?$/, async (req, res) => {
|
||||
@@ -287,6 +287,7 @@ export default (router, tpl) => {
|
||||
enable_cleanup: getEnableCleanup(),
|
||||
shitpost_mode: getShitpostMode(),
|
||||
enable_cleanup_config: cfg.websrv.enable_cleanup !== false,
|
||||
default_feed_layout: getDefaultFeedLayout(),
|
||||
tmp: null
|
||||
}, req)
|
||||
});
|
||||
@@ -618,6 +619,8 @@ export default (router, tpl) => {
|
||||
const registration_open = req.post.registration_open === 'on' ? 'true' : 'false';
|
||||
const min_tags = isNaN(parseInt(req.post.min_tags)) ? 3 : Math.max(0, parseInt(req.post.min_tags));
|
||||
const trusted_uploads = Math.max(0, parseInt(req.post.trusted_uploads) ?? 3);
|
||||
const raw_feed_layout = parseInt(req.post.default_feed_layout, 10);
|
||||
const default_feed_layout = (!isNaN(raw_feed_layout) && raw_feed_layout >= 0 && raw_feed_layout <= 3) ? raw_feed_layout : getDefaultFeedLayout();
|
||||
|
||||
await db`INSERT INTO site_settings (key, value) VALUES ('manual_approval', ${manual_approval}) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value`;
|
||||
|
||||
@@ -626,13 +629,14 @@ export default (router, tpl) => {
|
||||
setRegistrationOpen(registration_open === 'true');
|
||||
}
|
||||
|
||||
|
||||
await db`INSERT INTO site_settings (key, value) VALUES ('min_tags', ${min_tags.toString()}) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value`;
|
||||
await db`INSERT INTO site_settings (key, value) VALUES ('trusted_uploads', ${trusted_uploads.toString()}) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value`;
|
||||
await db`INSERT INTO site_settings (key, value) VALUES ('default_feed_layout', ${default_feed_layout.toString()}) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value`;
|
||||
|
||||
setManualApproval(manual_approval === 'true');
|
||||
setMinTags(min_tags);
|
||||
setTrustedUploads(trusted_uploads);
|
||||
setDefaultFeedLayout(default_feed_layout);
|
||||
|
||||
if (req.headers['x-requested-with'] === 'XMLHttpRequest') {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
@@ -642,7 +646,8 @@ export default (router, tpl) => {
|
||||
manual_approval: getManualApproval(),
|
||||
registration_open: getRegistrationOpen(),
|
||||
min_tags: getMinTags(),
|
||||
trusted_uploads: getTrustedUploads()
|
||||
trusted_uploads: getTrustedUploads(),
|
||||
default_feed_layout: getDefaultFeedLayout()
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
@@ -295,19 +295,34 @@ export default router => {
|
||||
}
|
||||
});
|
||||
|
||||
// Update New Layout visibility preference
|
||||
// Update feed layout preference (0=grid, 1=modern, 2=feed/instagram, 3=youtube)
|
||||
group.put(/\/layout/, lib.loggedin, async (req, res) => {
|
||||
const use_new_layout = req.post.use_new_layout === true || req.post.use_new_layout === 'true';
|
||||
const raw = req.post.feed_layout !== undefined ? req.post.feed_layout : req.post.use_new_layout;
|
||||
let feed_layout;
|
||||
|
||||
// Backward compat: if old boolean use_new_layout was sent, map to int
|
||||
if (req.post.feed_layout === undefined && req.post.use_new_layout !== undefined) {
|
||||
feed_layout = (req.post.use_new_layout === true || req.post.use_new_layout === 'true') ? 1 : 0;
|
||||
} else {
|
||||
feed_layout = parseInt(raw, 10);
|
||||
}
|
||||
|
||||
if (isNaN(feed_layout) || feed_layout < 0 || feed_layout > 3) {
|
||||
return res.json({ success: false, msg: 'Invalid layout value: must be 0–3' }, 400);
|
||||
}
|
||||
|
||||
try {
|
||||
await db`
|
||||
update user_options
|
||||
set use_new_layout = ${use_new_layout}
|
||||
set feed_layout = ${feed_layout},
|
||||
use_new_layout = ${feed_layout === 1}
|
||||
where user_id = ${+req.session.id}
|
||||
`;
|
||||
// Sync session immediately
|
||||
if (req.session) req.session.use_new_layout = use_new_layout;
|
||||
return res.json({ success: true, use_new_layout }, 200);
|
||||
if (req.session) {
|
||||
req.session.feed_layout = feed_layout;
|
||||
req.session.use_new_layout = feed_layout === 1;
|
||||
}
|
||||
return res.json({ success: true, feed_layout }, 200);
|
||||
} catch (e) {
|
||||
console.error('Update Layout pref error:', e);
|
||||
return res.json({ success: false, msg: 'Error updating preference' }, 500);
|
||||
|
||||
@@ -2,6 +2,7 @@ import cfg from "../config.mjs";
|
||||
import db from "../sql.mjs";
|
||||
import lib from "../lib.mjs";
|
||||
import f0cklib from "../routeinc/f0cklib.mjs";
|
||||
import { getDefaultFeedLayout } from "../settings.mjs";
|
||||
|
||||
const auth = async (req, res, next) => {
|
||||
if (!req.session)
|
||||
@@ -320,6 +321,15 @@ export default (router, tpl) => {
|
||||
// Only inject session for authenticated users to avoid showing member UI to guests
|
||||
data.session = (req.session && req.session.user) ? { ...req.session } : false;
|
||||
|
||||
// Pre-compute feed layout class (avoids template engine issues with complex ternaries)
|
||||
// Logic: use user's own feed_layout if they explicitly set one (> 0),
|
||||
// otherwise fall back to the site-wide default set in the admin dashboard.
|
||||
const userFeedLayout = data.session ? parseInt(data.session.feed_layout, 10) : 0;
|
||||
const siteFeedLayout = getDefaultFeedLayout();
|
||||
const rawFeedLayout = (userFeedLayout > 0) ? userFeedLayout : siteFeedLayout;
|
||||
const feedLayoutNum = (!isNaN(rawFeedLayout) && rawFeedLayout >= 0 && rawFeedLayout <= 3) ? rawFeedLayout : 0;
|
||||
data.feed_layout_class = 'layout-' + feedLayoutNum;
|
||||
|
||||
// Precompute boolean helpers for template @if() — the flummpress template engine uses a
|
||||
// non-greedy regex to parse @if(condition) and stops at the FIRST ')' it encounters.
|
||||
// This means any nested parens (e.g. indexOf('x'), .some(fn), (a || b)) inside @if()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import db from "../sql.mjs";
|
||||
import lib from "../lib.mjs";
|
||||
import security from "../security.mjs";
|
||||
import { getRegistrationOpen, getDefaultLayout } from "../settings.mjs";
|
||||
import { getRegistrationOpen, getDefaultLayout, getDefaultFeedLayout } from "../settings.mjs";
|
||||
import { sendMail } from "../../lib/smtp.mjs";
|
||||
import cfg from "../config.mjs";
|
||||
import crypto from "crypto";
|
||||
@@ -145,8 +145,8 @@ export default (router, tpl) => {
|
||||
const avatarFile = 'default.png';
|
||||
|
||||
await db`
|
||||
insert into user_options (user_id, mode, theme, fullscreen, avatar, avatar_file, use_new_layout, disable_autoplay, disable_swiping)
|
||||
values (${userId}, 3, 'amoled', 0, ${avatarId}, ${avatarFile}, ${getDefaultLayout() === 'modern'}, ${cfg.websrv.enable_autoplay === false}, ${cfg.websrv.enable_swiping === false})
|
||||
insert into user_options (user_id, mode, theme, fullscreen, avatar, avatar_file, use_new_layout, feed_layout, disable_autoplay, disable_swiping)
|
||||
values (${userId}, 3, 'amoled', 0, ${avatarId}, ${avatarFile}, ${getDefaultFeedLayout() === 1}, ${getDefaultFeedLayout()}, ${cfg.websrv.enable_autoplay === false}, ${cfg.websrv.enable_swiping === false})
|
||||
`;
|
||||
} catch (err) {
|
||||
console.error(`[REGISTER] DB Error during user creation:`, err);
|
||||
|
||||
@@ -8,6 +8,7 @@ let bypass_duplicate_check = false;
|
||||
let protect_files = false;
|
||||
let private_messages = true;
|
||||
let default_layout = 'modern';
|
||||
let default_feed_layout = 0;
|
||||
let enable_pdf = false;
|
||||
let enable_cleanup = false;
|
||||
let cleanup_start_date = '';
|
||||
@@ -62,6 +63,12 @@ export const setPrivateMessages = (val) => private_messages = !!val;
|
||||
export const getDefaultLayout = () => default_layout;
|
||||
export const setDefaultLayout = (val) => default_layout = (val === 'legacy' ? 'legacy' : 'modern');
|
||||
|
||||
export const getDefaultFeedLayout = () => default_feed_layout;
|
||||
export const setDefaultFeedLayout = (val) => {
|
||||
const parsed = parseInt(val, 10);
|
||||
default_feed_layout = (!isNaN(parsed) && parsed >= 0 && parsed <= 3) ? parsed : 0;
|
||||
};
|
||||
|
||||
export const getLogUserIps = () => !!cfg.websrv.log_user_ips;
|
||||
export const setLogUserIps = (val) => {}; // No-op, strictly config-based
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { handleHallImageUpload, handleHallImageDelete, handleHallDelete, handleH
|
||||
import { handleMetaExtract } from "./meta_extract_handler.mjs";
|
||||
import { handleMetaStrip } from "./meta_strip_handler.mjs";
|
||||
import { handleCommentUpload } from "./comment_upload_handler.mjs";
|
||||
import { getManualApproval, setManualApproval, getMinTags, setMinTags, getRegistrationOpen, setRegistrationOpen, getTrustedUploads, setTrustedUploads, getBypassDuplicateCheck, setBypassDuplicateCheck, getProtectFiles, setProtectFiles, getPrivateMessages, setPrivateMessages, getDefaultLayout, setDefaultLayout, getEnablePdf, setEnablePdf, getEnableCleanup, setEnableCleanup, getCleanupStartDate, setCleanupStartDate, getCleanupEndDate, setCleanupEndDate, getLogUserIps, setLogUserIps, getHashUserIps, setHashUserIps, getShitpostMode, setShitpostMode } from "./inc/settings.mjs";
|
||||
import { getManualApproval, setManualApproval, getMinTags, setMinTags, getRegistrationOpen, setRegistrationOpen, getTrustedUploads, setTrustedUploads, getBypassDuplicateCheck, setBypassDuplicateCheck, getProtectFiles, setProtectFiles, getPrivateMessages, setPrivateMessages, getDefaultLayout, setDefaultLayout, getDefaultFeedLayout, setDefaultFeedLayout, getEnablePdf, setEnablePdf, getEnableCleanup, setEnableCleanup, getCleanupStartDate, setCleanupStartDate, getCleanupEndDate, setCleanupEndDate, getLogUserIps, setLogUserIps, getHashUserIps, setHashUserIps, getShitpostMode, setShitpostMode } from "./inc/settings.mjs";
|
||||
import { updateHallsCache, getHalls } from "./inc/halls_cache.mjs";
|
||||
import { createI18n } from "./inc/i18n.mjs";
|
||||
import security from "./inc/security.mjs";
|
||||
@@ -504,7 +504,7 @@ process.on('uncaughtException', err => {
|
||||
|
||||
if (req.cookies.session) {
|
||||
const user = await db`
|
||||
select "user".id, "user".login, "user".user, "user".admin, "user".is_moderator, "user".banned, "user".ban_reason, "user".ban_expires, "user".force_password_change, "user_sessions".id as sess_id, "user_sessions".csrf_token, "user_options".mode, "user_options".theme, "user_options".fullscreen, "user_options".excluded_tags, "user_options".avatar, "user_options".avatar_file, "user_options".show_motd, "user_options".strict_mode, "user_options".show_background, "user_options".use_new_layout, "user_options".username_color, "user_options".font, "user_options".disable_autoplay, "user_options".disable_swiping, "user_options".description, "user_options".display_name, COALESCE("user_options".min_xd_score, 0) as min_xd_score, "user_options".ruffle_volume, "user_options".ruffle_background, "user_options".quote_emojis, "user_options".embed_youtube_in_comments, "user_options".hide_koepfe, "user_options".language, "user_options".use_alternative_infobox, "user_options".receive_system_notifications, "user_options".receive_user_notifications, "user_options".do_not_disturb, "user_options".comment_display_mode, "user_options".force_comment_display_mode
|
||||
select "user".id, "user".login, "user".user, "user".admin, "user".is_moderator, "user".banned, "user".ban_reason, "user".ban_expires, "user".force_password_change, "user_sessions".id as sess_id, "user_sessions".csrf_token, "user_options".mode, "user_options".theme, "user_options".fullscreen, "user_options".excluded_tags, "user_options".avatar, "user_options".avatar_file, "user_options".show_motd, "user_options".strict_mode, "user_options".show_background, "user_options".use_new_layout, "user_options".feed_layout, "user_options".username_color, "user_options".font, "user_options".disable_autoplay, "user_options".disable_swiping, "user_options".description, "user_options".display_name, COALESCE("user_options".min_xd_score, 0) as min_xd_score, "user_options".ruffle_volume, "user_options".ruffle_background, "user_options".quote_emojis, "user_options".embed_youtube_in_comments, "user_options".hide_koepfe, "user_options".language, "user_options".use_alternative_infobox, "user_options".receive_system_notifications, "user_options".receive_user_notifications, "user_options".do_not_disturb, "user_options".comment_display_mode, "user_options".force_comment_display_mode
|
||||
from "user_sessions"
|
||||
left join "user" on "user".id = "user_sessions".user_id
|
||||
left join "user_options" on "user_options".user_id = "user_sessions".user_id
|
||||
@@ -989,6 +989,19 @@ process.on('uncaughtException', err => {
|
||||
console.log(`[BOOT] Default layout set to: ${getDefaultLayout()}`);
|
||||
}
|
||||
|
||||
// Fetch default_feed_layout from DB site_settings
|
||||
try {
|
||||
const dflSetting = await db`SELECT value FROM site_settings WHERE key = 'default_feed_layout' LIMIT 1`;
|
||||
if (dflSetting.length > 0) {
|
||||
setDefaultFeedLayout(parseInt(dflSetting[0].value, 10));
|
||||
console.log(`[BOOT] Default feed layout loaded: ${getDefaultFeedLayout()}`);
|
||||
} else {
|
||||
console.log(`[BOOT] No default_feed_layout setting found, defaulting to 0 (Grid)`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(`[BOOT] default_feed_layout fetch failed:`, e.message);
|
||||
}
|
||||
|
||||
// Fetch about_text from database
|
||||
try {
|
||||
const aboutSetting = await db`SELECT value FROM site_settings WHERE key = 'about_text' LIMIT 1`;
|
||||
@@ -1076,6 +1089,7 @@ process.on('uncaughtException', err => {
|
||||
matrix_enabled: cfg.clients.find(c => c.type === 'matrix')?.enabled || false,
|
||||
ts: Date.now(),
|
||||
get default_layout() { return getDefaultLayout(); },
|
||||
get default_feed_layout() { return getDefaultFeedLayout(); },
|
||||
show_koepfe: !!cfg.websrv.show_koepfe,
|
||||
allow_language_change: cfg.websrv.allow_language_change !== false,
|
||||
enable_xd_score: !!cfg.websrv.enable_xd_score,
|
||||
|
||||
Reference in New Issue
Block a user