diff --git a/.gitignore b/.gitignore index 42a1b3c..8a0aca8 100644 --- a/.gitignore +++ b/.gitignore @@ -72,4 +72,6 @@ link-plugins.sh test.sh .docker/** -!**/.gitkeep \ No newline at end of file +!**/.gitkeep +# stryker temp files +.stryker-tmp diff --git a/.strykerignore b/.strykerignore new file mode 100644 index 0000000..d82c3c2 --- /dev/null +++ b/.strykerignore @@ -0,0 +1,3 @@ +build/ +public/ +plugins/ diff --git a/dump.rdb b/dump.rdb index d7dcdca..4cd026c 100644 Binary files a/dump.rdb and b/dump.rdb differ diff --git a/nodebb-theme-harmony/plugin.json b/nodebb-theme-harmony/plugin.json index 9a5bb19..211ca8b 100644 --- a/nodebb-theme-harmony/plugin.json +++ b/nodebb-theme-harmony/plugin.json @@ -12,7 +12,12 @@ { "hook": "filter:teasers.configureStripTags", "method": "filterTeasersConfigureStripTags"} ], "scripts": [ - "public/harmony.js" + "public/harmony.js", + "public/darkmode.js", + "public/styles/darkmode.css" + ], + "css": [ + "public/styles/darkmode.css" ], "modules": { "../admin/plugins/harmony.js": "public/admin.js", diff --git a/nodebb-theme-harmony/public/darkmode.js b/nodebb-theme-harmony/public/darkmode.js new file mode 100644 index 0000000..b85f0d4 --- /dev/null +++ b/nodebb-theme-harmony/public/darkmode.js @@ -0,0 +1,37 @@ +// $(document).ready(function () { +// // Check user's saved preference and apply dark mode +// if (config.user && config.user.settings.darkMode) { +// $('body').addClass('dark-mode'); +// $('#darkModeToggle').prop('checked', true); +// } + +// // Toggle dark mode when user changes the setting +// $('#darkModeToggle').change(function () { +// const isDarkMode = $(this).prop('checked'); +// $('body').toggleClass('dark-mode', isDarkMode); +// $.post('/api/user/settings', { darkMode: isDarkMode ? '1' : '0' }); +// }); +// }); + +document.addEventListener("DOMContentLoaded", function () { + const darkModeToggle = document.getElementById("darkModeToggle"); + + function applyDarkMode(isEnabled) { + if (isEnabled) { + document.body.classList.add("dark-mode"); + localStorage.setItem("darkMode", "true"); + } else { + document.body.classList.remove("dark-mode"); + localStorage.setItem("darkMode", "false"); + } + } + + // Load setting from local storage + applyDarkMode(localStorage.getItem("darkMode") === "true"); + + if (darkModeToggle) { + darkModeToggle.addEventListener("change", function () { + applyDarkMode(this.checked); + }); + } +}); diff --git a/nodebb-theme-harmony/public/harmony.js b/nodebb-theme-harmony/public/harmony.js index 6387055..bde9e94 100644 --- a/nodebb-theme-harmony/public/harmony.js +++ b/nodebb-theme-harmony/public/harmony.js @@ -11,6 +11,28 @@ $(document).ready(function () { fixPlaceholders(); fixSidebarOverflow(); + const darkModeToggle = document.getElementById("darkModeToggle"); + + if (darkModeToggle) { + // Apply stored preference + if (localStorage.getItem("darkMode") === "enabled") { + document.body.classList.add("dark-mode"); + darkModeToggle.checked = true; + } + + // Listen for changes + darkModeToggle.addEventListener("change", function () { + if (this.checked) { + document.body.classList.add("dark-mode"); + localStorage.setItem("darkMode", "enabled"); + } else { + document.body.classList.remove("dark-mode"); + localStorage.setItem("darkMode", "disabled"); + } + }); + } + + function setupSkinSwitcher() { $('[component="skinSwitcher"]').on('click', '.dropdown-item', function () { const skin = $(this).attr('data-value'); diff --git a/nodebb-theme-harmony/templates/account/settings.tpl b/nodebb-theme-harmony/templates/account/settings.tpl index c4c78a1..7ae1c8a 100644 --- a/nodebb-theme-harmony/templates/account/settings.tpl +++ b/nodebb-theme-harmony/templates/account/settings.tpl @@ -65,11 +65,19 @@
[[user:browsing]]
+
+
+ + +
+ + + {{{ if inTopicSearchAvailable }}}
@@ -92,6 +100,11 @@
[[global:pagination]]
+
+ + +
+
diff --git a/nodebb-theme-harmony/templates/account/theme.tpl b/nodebb-theme-harmony/templates/account/theme.tpl index 67fdbc7..5772006 100644 --- a/nodebb-theme-harmony/templates/account/theme.tpl +++ b/nodebb-theme-harmony/templates/account/theme.tpl @@ -59,6 +59,13 @@
+
+ + +
+ \ No newline at end of file diff --git a/nodebb-theme-harmony/templates/partials/topic/post.tpl b/nodebb-theme-harmony/templates/partials/topic/post.tpl index e2e92ad..512c7c3 100644 --- a/nodebb-theme-harmony/templates/partials/topic/post.tpl +++ b/nodebb-theme-harmony/templates/partials/topic/post.tpl @@ -39,7 +39,11 @@
{generateWroteReplied(@value, config.timeagoCutoff)} - + + + + + [[global:last-edited-by, {posts.editor.username}]]
diff --git a/src/cli/index.js b/src/cli/index.js index e6f0485..dfa49e7 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -103,21 +103,43 @@ global.env = process.env.NODE_ENV || 'production'; prestart.setupWinston(); // Alternate configuration file support +// const configFile = path.resolve(paths.baseDir, nconf.get('config') || 'config.json'); +// const configExists = file.existsSync(configFile) || (nconf.get('url') && nconf.get('secret') && nconf.get('database')); + +// prestart.loadConfig(configFile); +// prestart.versionCheck(); + +// if (!configExists && process.argv[2] !== 'setup') { +// require('./setup').webInstall(); +// return; +// } + +// if (configExists) { +// process.env.CONFIG = configFile; +// } + + +//code change by evelyn const configFile = path.resolve(paths.baseDir, nconf.get('config') || 'config.json'); const configExists = file.existsSync(configFile) || (nconf.get('url') && nconf.get('secret') && nconf.get('database')); prestart.loadConfig(configFile); prestart.versionCheck(); -if (!configExists && process.argv[2] !== 'setup') { - require('./setup').webInstall(); - return; +function checkAndSetup() { + if (!configExists && process.argv[2] !== 'setup') { + require('./setup').webInstall(); + return; // ✅ Now inside a function, so no syntax error + } } +checkAndSetup(); + if (configExists) { - process.env.CONFIG = configFile; + process.env.CONFIG = configFile; } + // running commands program .command('start') diff --git a/src/user/settings.js b/src/user/settings.js index d85a712..c688e58 100644 --- a/src/user/settings.js +++ b/src/user/settings.js @@ -24,8 +24,10 @@ module.exports = function (User) { let settings = await db.getObject(`user:${uid}:settings`); settings = settings || {}; settings.uid = uid; + settings.darkMode = settings.darkMode || false; // Retrieve dark mode setting return await onSettingsLoaded(uid, settings); }; + User.getMultipleUserSettings = async function (uids) { if (!Array.isArray(uids) || !uids.length) { @@ -148,6 +150,7 @@ module.exports = function (User) { categoryWatchState: data.categoryWatchState, categoryTopicSort: data.categoryTopicSort, topicPostSort: data.topicPostSort, + darkMode: data.darkMode || false, // Save dark mode preference }; const notificationTypes = await notifications.getAllNotificationTypes(); notificationTypes.forEach((notificationType) => { @@ -172,7 +175,9 @@ module.exports = function (User) { if (parseInt(uid, 10) <= 0) { return; } - + if (key === 'darkMode') { + value = value ? true : false; // Ensure it's a boolean + } await db.setObjectField(`user:${uid}:settings`, key, value); }; }; diff --git a/stryker.config.json b/stryker.config.json new file mode 100644 index 0000000..010d6f8 --- /dev/null +++ b/stryker.config.json @@ -0,0 +1,21 @@ +{ + "$schema": "./node_modules/@stryker-mutator/core/schema/stryker-schema.json", + "packageManager": "npm", + "reporters": [ + "html", + "clear-text", + "progress" + ], + "testRunner": "mocha", + "coverageAnalysis": "perTest", + "mutate": [ + "src/**/*.js" + ], + "sandbox": { + "filePatterns": [ + "!build/**", + "!public/**", + "!plugins/**" + ] + } +} diff --git a/stryker_output.txt b/stryker_output.txt new file mode 100644 index 0000000..b070d89 --- /dev/null +++ b/stryker_output.txt @@ -0,0 +1,23 @@ +14:23:35 (34493) WARN OptionsValidator Unknown stryker config option "sandbox". +14:23:35 (34493) WARN OptionsValidator Possible causes: + * Is it a typo on your end? + * Did you only write this property as a comment? If so, please postfix it with "_comment". + * You might be missing a plugin that is supposed to use it. Stryker loaded plugins from: ["@stryker-mutator/*"] + * The plugin that is using it did not contribute explicit validation. + (disable "warnings.unknownOptions" to ignore this warning) +14:23:35 (34493) INFO ProjectReader Found 548 of 10828 file(s) to be mutated. +14:23:38 (34493) INFO Instrumenter Instrumented 548 source file(s) with 55842 mutant(s) +14:23:39 (34493) INFO ConcurrencyTokenProvider Creating 7 test runner process(es). +14:23:40 (34493) ERROR Stryker Unexpected error occurred while running Stryker Error: ENOTSUP: operation not supported on socket, copyfile '/Users/evelynlo/nodebb-s25-puffers/build/public/plugins/nodebb-plugin-markdown/styles' -> '/Users/evelynlo/nodebb-s25-puffers/.stryker-tmp/sandbox-oxK0Gt/build/public/plugins/nodebb-plugin-markdown/styles' + at async Object.copyFile (node:internal/fs/promises:621:10) + at async FileSystemAction.execute (file:///Users/evelynlo/nodebb-s25-puffers/node_modules/@stryker-mutator/core/dist/src/fs/file-system.js:16:28) + at async file:///Users/evelynlo/nodebb-s25-puffers/node_modules/@stryker-mutator/core/dist/src/fs/file-system.js:33:9 { + errno: -45, + code: 'ENOTSUP', + syscall: 'copyfile', + path: '/Users/evelynlo/nodebb-s25-puffers/build/public/plugins/nodebb-plugin-markdown/styles', + dest: '/Users/evelynlo/nodebb-s25-puffers/.stryker-tmp/sandbox-oxK0Gt/build/public/plugins/nodebb-plugin-markdown/styles' +} +14:23:40 (34493) INFO Stryker This might be a known problem with a solution documented in our troubleshooting guide. +14:23:40 (34493) INFO Stryker You can find it at https://stryker-mutator.io/docs/stryker-js/troubleshooting/ +14:23:40 (34493) INFO Stryker Still having trouble figuring out what went wrong? Try `npx stryker run --fileLogLevel trace --logLevel debug` to get some more info.