diff --git a/commafeed-client/package-lock.json b/commafeed-client/package-lock.json index 57610842..d0810c66 100644 --- a/commafeed-client/package-lock.json +++ b/commafeed-client/package-lock.json @@ -62,6 +62,7 @@ "@types/tinycon": "^0.6.5", "@vitejs/plugin-react": "^4.3.1", "babel-plugin-macros": "^3.1.0", + "jsdom": "^25.0.0", "rollup-plugin-visualizer": "^5.12.0", "typescript": "^5.6.2", "vite": "^5.4.3", @@ -3292,12 +3293,71 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/cssstyle": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", + "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", + "dev": true, + "dependencies": { + "rrweb-cssom": "^0.7.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dev": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", @@ -3383,6 +3443,12 @@ } } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, "node_modules/decko": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decko/-/decko-1.2.0.tgz", @@ -3597,7 +3663,6 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "license": "BSD-2-Clause", - "peer": true, "engines": { "node": ">=0.12" }, @@ -4426,6 +4491,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/htmlparser2": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", @@ -4446,6 +4523,19 @@ "entities": "^4.5.0" } }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/http2-client": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", @@ -4909,6 +4999,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -5194,6 +5290,80 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdom": { + "version": "25.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.0.tgz", + "integrity": "sha512-OhoFVT59T7aEq75TVw9xxEfkXgacpqAhQaYgP9y/fDqWQCMB/b1H66RfmPm/MaeaAIU9nDwMOVTlPN51+ao6CQ==", + "dev": true, + "dependencies": { + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.4", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dev": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -5782,6 +5952,12 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/nwsapi": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", + "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", + "dev": true + }, "node_modules/oas-kit-common": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz", @@ -6187,7 +6363,6 @@ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", "license": "MIT", - "peer": true, "dependencies": { "entities": "^4.4.0" }, @@ -6482,6 +6657,12 @@ "node": ">=16.0.0" } }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -6492,6 +6673,12 @@ "node": ">=6" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, "node_modules/raf": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", @@ -7037,6 +7224,12 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, "node_modules/reselect": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", @@ -7166,6 +7359,12 @@ "node": ">= 8" } }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "dev": true + }, "node_modules/rst-selector-parser": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz", @@ -7269,6 +7468,18 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -7693,6 +7904,12 @@ "url": "https://github.com/Mermade/oas-kit?sponsor=1" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "node_modules/tabbable": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", @@ -7793,6 +8010,21 @@ "node": ">=8.0" } }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -8019,6 +8251,15 @@ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "license": "MIT" }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/unraw": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unraw/-/unraw-3.0.0.tgz", @@ -8062,6 +8303,16 @@ "integrity": "sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==", "license": "MIT" }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/url-template": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", @@ -8809,6 +9060,18 @@ "vitest": ">=2.0.0" } }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -8836,7 +9099,6 @@ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", "license": "MIT", - "peer": true, "dependencies": { "iconv-lite": "0.6.3" }, @@ -8849,7 +9111,6 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", - "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -8862,7 +9123,6 @@ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -9002,6 +9262,42 @@ "dev": true, "license": "ISC" }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/commafeed-client/package.json b/commafeed-client/package.json index 3bf1dbcf..ef453901 100644 --- a/commafeed-client/package.json +++ b/commafeed-client/package.json @@ -69,6 +69,7 @@ "@types/tinycon": "^0.6.5", "@vitejs/plugin-react": "^4.3.1", "babel-plugin-macros": "^3.1.0", + "jsdom": "^25.0.0", "rollup-plugin-visualizer": "^5.12.0", "typescript": "^5.6.2", "vite": "^5.4.3", diff --git a/commafeed-client/src/app/entries/thunks.ts b/commafeed-client/src/app/entries/thunks.ts index eb9eca28..afd094d1 100644 --- a/commafeed-client/src/app/entries/thunks.ts +++ b/commafeed-client/src/app/entries/thunks.ts @@ -166,22 +166,34 @@ export const selectEntry = createAppAsyncThunk( }) if (arg.scrollToEntry) { + const viewMode = state.user.localSettings.viewMode + + const entryIndex = state.entries.entries.indexOf(entry) + const entriesToKeepOnTopWhenScrolling = + viewMode === "expanded" ? 0 : Math.min(state.user.settings?.entriesToKeepOnTopWhenScrolling ?? 0, entryIndex) + const entryToScrollTo = state.entries.entries[entryIndex - entriesToKeepOnTopWhenScrolling] + const entryElement = document.getElementById(Constants.dom.entryId(entry)) - if (entryElement) { + const entryElementToScrollTo = document.getElementById(Constants.dom.entryId(entryToScrollTo)) + if (entryElement && entryElementToScrollTo) { const scrollMode = state.user.settings?.scrollMode - const entryEntirelyVisible = Constants.layout.isTopVisible(entryElement) && Constants.layout.isBottomVisible(entryElement) + const entryEntirelyVisible = + Constants.layout.isTopVisible(entryElementToScrollTo) && Constants.layout.isBottomVisible(entryElement) if (scrollMode === "always" || (scrollMode === "if_needed" && !entryEntirelyVisible)) { const scrollSpeed = state.user.settings?.scrollSpeed + const margin = viewMode === "detailed" ? 8 : 3 thunkApi.dispatch(entriesSlice.actions.setScrollingToEntry(true)) - scrollToEntry(entryElement, scrollSpeed, () => thunkApi.dispatch(entriesSlice.actions.setScrollingToEntry(false))) + scrollToEntry(entryElementToScrollTo, margin, scrollSpeed, () => + thunkApi.dispatch(entriesSlice.actions.setScrollingToEntry(false)) + ) } } } } ) -const scrollToEntry = (entryElement: HTMLElement, scrollSpeed: number | undefined, onScrollEnded: () => void) => { +const scrollToEntry = (entryElement: HTMLElement, margin: number, scrollSpeed: number | undefined, onScrollEnded: () => void) => { const header = document.getElementById(Constants.dom.headerId)?.getBoundingClientRect() - const offset = (header?.bottom ?? 0) + 3 + const offset = (header?.bottom ?? 0) + margin scrollToWithCallback({ options: { top: entryElement.offsetTop - offset, diff --git a/commafeed-client/src/app/store.ts b/commafeed-client/src/app/store.ts index a4eb1f4c..e73a31d5 100644 --- a/commafeed-client/src/app/store.ts +++ b/commafeed-client/src/app/store.ts @@ -3,6 +3,7 @@ import { entriesSlice } from "app/entries/slice" import { redirectSlice } from "app/redirect/slice" import { serverSlice } from "app/server/slice" import { treeSlice } from "app/tree/slice" +import type { ViewMode } from "app/types" import { userSlice } from "app/user/slice" import { type TypedUseSelectorHook, useDispatch, useSelector } from "react-redux" @@ -14,7 +15,20 @@ export const reducers = { user: userSlice.reducer, } -export const store = configureStore({ reducer: reducers }) +export const store = configureStore({ + reducer: reducers, + preloadedState: { + user: { + localSettings: { + viewMode: localStorage.getItem("view-mode") as ViewMode, + }, + }, + }, +}) +store.subscribe(() => { + const state = store.getState() + localStorage.setItem("view-mode", state.user.localSettings.viewMode) +}) export type RootState = ReturnType export type AppDispatch = typeof store.dispatch diff --git a/commafeed-client/src/app/types.ts b/commafeed-client/src/app/types.ts index 6fc41c6b..b44a10b4 100644 --- a/commafeed-client/src/app/types.ts +++ b/commafeed-client/src/app/types.ts @@ -243,6 +243,7 @@ export interface Settings { customJs?: string scrollSpeed: number scrollMode: ScrollMode + entriesToKeepOnTopWhenScrolling: number starIconDisplayMode: IconDisplayMode externalLinkIconDisplayMode: IconDisplayMode markAllAsReadConfirmation: boolean diff --git a/commafeed-client/src/app/user/slice.ts b/commafeed-client/src/app/user/slice.ts index 576c8e1f..56fe5025 100644 --- a/commafeed-client/src/app/user/slice.ts +++ b/commafeed-client/src/app/user/slice.ts @@ -1,9 +1,10 @@ import { t } from "@lingui/macro" import { showNotification } from "@mantine/notifications" -import { createSlice, isAnyOf } from "@reduxjs/toolkit" -import type { Settings, UserModel } from "app/types" +import { type PayloadAction, createSlice, isAnyOf } from "@reduxjs/toolkit" +import type { Settings, UserModel, ViewMode } from "app/types" import { changeCustomContextMenu, + changeEntriesToKeepOnTopWhenScrolling, changeExternalLinkIconDisplayMode, changeLanguage, changeMarkAllAsReadConfirmation, @@ -25,16 +26,27 @@ import { interface UserState { settings?: Settings + localSettings: { + viewMode: ViewMode + } profile?: UserModel tags?: string[] } -const initialState: UserState = {} +const initialState: UserState = { + localSettings: { + viewMode: "detailed", + }, +} export const userSlice = createSlice({ name: "user", initialState, - reducers: {}, + reducers: { + setViewMode: (state, action: PayloadAction) => { + state.localSettings.viewMode = action.payload + }, + }, extraReducers: builder => { builder.addCase(reloadSettings.fulfilled, (state, action) => { state.settings = action.payload @@ -73,6 +85,10 @@ export const userSlice = createSlice({ if (!state.settings) return state.settings.scrollMode = action.meta.arg }) + builder.addCase(changeEntriesToKeepOnTopWhenScrolling.pending, (state, action) => { + if (!state.settings) return + state.settings.entriesToKeepOnTopWhenScrolling = action.meta.arg + }) builder.addCase(changeStarIconDisplayMode.pending, (state, action) => { if (!state.settings) return state.settings.starIconDisplayMode = action.meta.arg @@ -112,6 +128,7 @@ export const userSlice = createSlice({ changeShowRead.fulfilled, changeScrollMarks.fulfilled, changeScrollMode.fulfilled, + changeEntriesToKeepOnTopWhenScrolling.fulfilled, changeStarIconDisplayMode.fulfilled, changeExternalLinkIconDisplayMode.fulfilled, changeMarkAllAsReadConfirmation.fulfilled, @@ -130,3 +147,5 @@ export const userSlice = createSlice({ ) }, }) + +export const { setViewMode } = userSlice.actions diff --git a/commafeed-client/src/app/user/thunks.ts b/commafeed-client/src/app/user/thunks.ts index 63a462d3..4148881e 100644 --- a/commafeed-client/src/app/user/thunks.ts +++ b/commafeed-client/src/app/user/thunks.ts @@ -43,6 +43,14 @@ export const changeScrollMode = createAppAsyncThunk("settings/scrollMode", (scro if (!settings) return client.user.saveSettings({ ...settings, scrollMode }) }) +export const changeEntriesToKeepOnTopWhenScrolling = createAppAsyncThunk( + "settings/entriesToKeepOnTopWhenScrolling", + (entriesToKeepOnTopWhenScrolling: number, thunkApi) => { + const { settings } = thunkApi.getState().user + if (!settings) return + client.user.saveSettings({ ...settings, entriesToKeepOnTopWhenScrolling }) + } +) export const changeStarIconDisplayMode = createAppAsyncThunk( "settings/starIconDisplayMode", (starIconDisplayMode: IconDisplayMode, thunkApi) => { diff --git a/commafeed-client/src/components/content/FeedEntries.tsx b/commafeed-client/src/components/content/FeedEntries.tsx index 6e4e1f0f..76bb909b 100644 --- a/commafeed-client/src/components/content/FeedEntries.tsx +++ b/commafeed-client/src/components/content/FeedEntries.tsx @@ -20,7 +20,6 @@ import { KeyboardShortcutsHelp } from "components/KeyboardShortcutsHelp" import { Loader } from "components/Loader" import { useBrowserExtension } from "hooks/useBrowserExtension" import { useMousetrap } from "hooks/useMousetrap" -import { useViewMode } from "hooks/useViewMode" import { useEffect } from "react" import { useContextMenu } from "react-contexify" import InfiniteScroll from "react-infinite-scroller" @@ -38,7 +37,7 @@ export function FeedEntries() { const scrollingToEntry = useAppSelector(state => state.entries.scrollingToEntry) const sidebarVisible = useAppSelector(state => state.tree.sidebarVisible) const customContextMenu = useAppSelector(state => state.user.settings?.customContextMenu) - const { viewMode } = useViewMode() + const viewMode = useAppSelector(state => state.user.localSettings.viewMode) const dispatch = useAppDispatch() const { openLinkInBackgroundTab } = useBrowserExtension() diff --git a/commafeed-client/src/components/content/FeedEntry.tsx b/commafeed-client/src/components/content/FeedEntry.tsx index 663d8b3f..e46f7a12 100644 --- a/commafeed-client/src/components/content/FeedEntry.tsx +++ b/commafeed-client/src/components/content/FeedEntry.tsx @@ -5,7 +5,6 @@ import type { Entry, ViewMode } from "app/types" import { FeedEntryCompactHeader } from "components/content/header/FeedEntryCompactHeader" import { FeedEntryHeader } from "components/content/header/FeedEntryHeader" import { useMobile } from "hooks/useMobile" -import { useViewMode } from "hooks/useViewMode" import type React from "react" import { useSwipeable } from "react-swipeable" import { tss } from "tss" @@ -95,7 +94,7 @@ const useStyles = tss }) export function FeedEntry(props: FeedEntryProps) { - const { viewMode } = useViewMode() + const viewMode = useAppSelector(state => state.user.localSettings.viewMode) const { classes, cx } = useStyles({ read: props.entry.read, expanded: props.expanded, diff --git a/commafeed-client/src/components/header/ProfileMenu.tsx b/commafeed-client/src/components/header/ProfileMenu.tsx index 4bc97a3a..a3305d17 100644 --- a/commafeed-client/src/components/header/ProfileMenu.tsx +++ b/commafeed-client/src/components/header/ProfileMenu.tsx @@ -14,7 +14,7 @@ import { client } from "app/client" import { redirectToAbout, redirectToAdminUsers, redirectToDonate, redirectToMetrics, redirectToSettings } from "app/redirect/thunks" import { useAppDispatch, useAppSelector } from "app/store" import type { ViewMode } from "app/types" -import { useViewMode } from "hooks/useViewMode" +import { setViewMode } from "app/user/slice" import { type ReactNode, useState } from "react" import { TbChartLine, @@ -92,9 +92,9 @@ const viewModeData: ViewModeControlItem[] = [ export function ProfileMenu(props: ProfileMenuProps) { const [opened, setOpened] = useState(false) - const { viewMode, setViewMode } = useViewMode() const profile = useAppSelector(state => state.user.profile) const admin = useAppSelector(state => state.user.profile?.admin) + const viewMode = useAppSelector(state => state.user.localSettings.viewMode) const dispatch = useAppDispatch() const { colorScheme, setColorScheme } = useMantineColorScheme() @@ -156,7 +156,7 @@ export function ProfileMenu(props: ProfileMenuProps) { orientation="vertical" data={viewModeData} value={viewMode} - onChange={e => setViewMode(e as ViewMode)} + onChange={e => dispatch(setViewMode(e as ViewMode))} mb="xs" /> diff --git a/commafeed-client/src/components/settings/DisplaySettings.tsx b/commafeed-client/src/components/settings/DisplaySettings.tsx index c3d9394a..31ee4133 100644 --- a/commafeed-client/src/components/settings/DisplaySettings.tsx +++ b/commafeed-client/src/components/settings/DisplaySettings.tsx @@ -1,12 +1,13 @@ import { Trans, msg } from "@lingui/macro" import { useLingui } from "@lingui/react" -import { Divider, Group, Radio, Select, SimpleGrid, Stack, Switch } from "@mantine/core" +import { Divider, Group, NumberInput, Radio, Select, SimpleGrid, Stack, Switch } from "@mantine/core" import type { ComboboxData } from "@mantine/core/lib/components/Combobox/Combobox.types" import { Constants } from "app/constants" import { useAppDispatch, useAppSelector } from "app/store" import type { IconDisplayMode, ScrollMode, SharingSettings } from "app/types" import { changeCustomContextMenu, + changeEntriesToKeepOnTopWhenScrolling, changeExternalLinkIconDisplayMode, changeLanguage, changeMarkAllAsReadConfirmation, @@ -29,6 +30,7 @@ export function DisplaySettings() { const showRead = useAppSelector(state => state.user.settings?.showRead) const scrollMarks = useAppSelector(state => state.user.settings?.scrollMarks) const scrollMode = useAppSelector(state => state.user.settings?.scrollMode) + const entriesToKeepOnTop = useAppSelector(state => state.user.settings?.entriesToKeepOnTopWhenScrolling) const starIconDisplayMode = useAppSelector(state => state.user.settings?.starIconDisplayMode) const externalLinkIconDisplayMode = useAppSelector(state => state.user.settings?.externalLinkIconDisplayMode) const markAllAsReadConfirmation = useAppSelector(state => state.user.settings?.markAllAsReadConfirmation) @@ -145,6 +147,14 @@ export function DisplaySettings() { + Entries to keep above the selected entry when scrolling} + description={Only applies to compact, cozy and detailed modes} + min={0} + value={entriesToKeepOnTop} + onChange={async value => await dispatch(changeEntriesToKeepOnTopWhenScrolling(+value))} + /> + Scroll smoothly when navigating between entries} checked={scrollSpeed ? scrollSpeed > 0 : false} diff --git a/commafeed-client/src/hooks/useViewMode.ts b/commafeed-client/src/hooks/useViewMode.ts deleted file mode 100644 index 94ad5414..00000000 --- a/commafeed-client/src/hooks/useViewMode.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { ViewMode } from "app/types" -import useLocalStorage from "use-local-storage" - -export function useViewMode() { - const [viewMode, setViewMode] = useLocalStorage("view-mode", "detailed") - return { viewMode, setViewMode } -} diff --git a/commafeed-client/src/locales/ar/messages.po b/commafeed-client/src/locales/ar/messages.po index ad2f6852..e294285f 100644 --- a/commafeed-client/src/locales/ar/messages.po +++ b/commafeed-client/src/locales/ar/messages.po @@ -321,6 +321,10 @@ msgstr "دخول" msgid "Enter your current password to change profile settings" msgstr "أدخل كلمة المرور الحالية لتغيير إعدادات ملف التعريف" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "اوووه!" diff --git a/commafeed-client/src/locales/ca/messages.po b/commafeed-client/src/locales/ca/messages.po index 34662549..819433d5 100644 --- a/commafeed-client/src/locales/ca/messages.po +++ b/commafeed-client/src/locales/ca/messages.po @@ -321,6 +321,10 @@ msgstr "Entra" msgid "Enter your current password to change profile settings" msgstr "introduïu la vostra contrasenya actual per canviar la configuració del perfil" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "Al mòbil, mostra els botons d'acció a la part inferior de la pantalla" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Vaja!" diff --git a/commafeed-client/src/locales/cs/messages.po b/commafeed-client/src/locales/cs/messages.po index 876c3b6c..eab11334 100644 --- a/commafeed-client/src/locales/cs/messages.po +++ b/commafeed-client/src/locales/cs/messages.po @@ -321,6 +321,10 @@ msgstr "Vstupte" msgid "Enter your current password to change profile settings" msgstr "Zadejte své aktuální heslo pro změnu nastavení profilu" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Jejda!" diff --git a/commafeed-client/src/locales/cy/messages.po b/commafeed-client/src/locales/cy/messages.po index eb090f34..49bf6d97 100644 --- a/commafeed-client/src/locales/cy/messages.po +++ b/commafeed-client/src/locales/cy/messages.po @@ -321,6 +321,10 @@ msgstr "Ewch i mewn" msgid "Enter your current password to change profile settings" msgstr "Rhowch eich cyfrinair presennol i newid gosodiadau proffil" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Wps!" diff --git a/commafeed-client/src/locales/da/messages.po b/commafeed-client/src/locales/da/messages.po index 93e18d5f..3a89fafb 100644 --- a/commafeed-client/src/locales/da/messages.po +++ b/commafeed-client/src/locales/da/messages.po @@ -321,6 +321,10 @@ msgstr "" msgid "Enter your current password to change profile settings" msgstr "Indtast din nuværende adgangskode for at ændre profilindstillinger" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Hovsa!" diff --git a/commafeed-client/src/locales/de/messages.po b/commafeed-client/src/locales/de/messages.po index 0abc5949..9c242850 100644 --- a/commafeed-client/src/locales/de/messages.po +++ b/commafeed-client/src/locales/de/messages.po @@ -321,6 +321,10 @@ msgstr "Eintreten" msgid "Enter your current password to change profile settings" msgstr "Geben Sie Ihr aktuelles Passwort ein, um die Profileinstellungen zu ändern" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "Auf mobilen Geräten die Aktion-Buttons am unteren Ende des Bildschirms anzeigen" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Ups!" diff --git a/commafeed-client/src/locales/en/messages.po b/commafeed-client/src/locales/en/messages.po index 661e7a44..1d402cf4 100644 --- a/commafeed-client/src/locales/en/messages.po +++ b/commafeed-client/src/locales/en/messages.po @@ -321,6 +321,10 @@ msgstr "Enter" msgid "Enter your current password to change profile settings" msgstr "Enter your current password to change profile settings" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "Entries to keep above the selected entry when scrolling" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "Entry headers" @@ -608,6 +612,10 @@ msgstr "On mobile" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "On mobile, show action buttons at the bottom of the screen" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "Only applies to compact, cozy and detailed modes" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Oops!" diff --git a/commafeed-client/src/locales/es/messages.po b/commafeed-client/src/locales/es/messages.po index ce4c4f01..07e2f534 100644 --- a/commafeed-client/src/locales/es/messages.po +++ b/commafeed-client/src/locales/es/messages.po @@ -321,6 +321,10 @@ msgstr "Entrar" msgid "Enter your current password to change profile settings" msgstr "Ingrese su contraseña actual para cambiar la configuración del perfil" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "¡Ups!" diff --git a/commafeed-client/src/locales/fa/messages.po b/commafeed-client/src/locales/fa/messages.po index 02c240c7..c52223a3 100644 --- a/commafeed-client/src/locales/fa/messages.po +++ b/commafeed-client/src/locales/fa/messages.po @@ -321,6 +321,10 @@ msgstr "وارد شوید" msgid "Enter your current password to change profile settings" msgstr "رمز عبور فعلی خود را برای تغییر تنظیمات نمایه وارد کنید" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "اوه!" diff --git a/commafeed-client/src/locales/fi/messages.po b/commafeed-client/src/locales/fi/messages.po index a1e874f7..38fafaf7 100644 --- a/commafeed-client/src/locales/fi/messages.po +++ b/commafeed-client/src/locales/fi/messages.po @@ -321,6 +321,10 @@ msgstr "" msgid "Enter your current password to change profile settings" msgstr "Anna nykyinen salasanasi muuttaaksesi profiiliasetuksia" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Hups!" diff --git a/commafeed-client/src/locales/fr/messages.po b/commafeed-client/src/locales/fr/messages.po index c0fea867..bd87f4f6 100644 --- a/commafeed-client/src/locales/fr/messages.po +++ b/commafeed-client/src/locales/fr/messages.po @@ -321,6 +321,10 @@ msgstr "Entrer" msgid "Enter your current password to change profile settings" msgstr "Entrez votre mot de passe actuel pour changer les paramètres du profil" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "En-têtes de l'entrée" @@ -608,6 +612,10 @@ msgstr "Version mobile" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "Sur mobile, afficher les boutons d'action en bas de l'écran" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Oups !" diff --git a/commafeed-client/src/locales/gl/messages.po b/commafeed-client/src/locales/gl/messages.po index 96334d72..4463f338 100644 --- a/commafeed-client/src/locales/gl/messages.po +++ b/commafeed-client/src/locales/gl/messages.po @@ -321,6 +321,10 @@ msgstr "Entra" msgid "Enter your current password to change profile settings" msgstr "Introduce o teu contrasinal actual para cambiar a configuración do perfil" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Vaia!" diff --git a/commafeed-client/src/locales/hu/messages.po b/commafeed-client/src/locales/hu/messages.po index 03fa65b0..0f04cde4 100644 --- a/commafeed-client/src/locales/hu/messages.po +++ b/commafeed-client/src/locales/hu/messages.po @@ -321,6 +321,10 @@ msgstr "" msgid "Enter your current password to change profile settings" msgstr "Adja meg jelenlegi jelszavát a profilbeállítások módosításához" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Hoppá!" diff --git a/commafeed-client/src/locales/id/messages.po b/commafeed-client/src/locales/id/messages.po index e71cd7ba..b9946539 100644 --- a/commafeed-client/src/locales/id/messages.po +++ b/commafeed-client/src/locales/id/messages.po @@ -321,6 +321,10 @@ msgstr "Masuk" msgid "Enter your current password to change profile settings" msgstr "Masukkan kata sandi Anda saat ini untuk mengubah pengaturan profil" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Ups!" diff --git a/commafeed-client/src/locales/it/messages.po b/commafeed-client/src/locales/it/messages.po index 5e752d0a..244573c2 100644 --- a/commafeed-client/src/locales/it/messages.po +++ b/commafeed-client/src/locales/it/messages.po @@ -321,6 +321,10 @@ msgstr "Invio" msgid "Enter your current password to change profile settings" msgstr "Inserisci la tua password attuale per modificare le impostazioni del profilo" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Ops!" diff --git a/commafeed-client/src/locales/ja/messages.po b/commafeed-client/src/locales/ja/messages.po index ae0c6f8d..e4c1bf4b 100644 --- a/commafeed-client/src/locales/ja/messages.po +++ b/commafeed-client/src/locales/ja/messages.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "PO-Revision-Date: \n" -"Last-Translator: https://github.com/dai \n" +"Last-Translator: https://github.com/dai\n" "Language-Team: \n" "Plural-Forms: \n" @@ -29,7 +29,6 @@ msgstr "<0>アカウントをお持ちですか?<1>ログインしてくだ msgid "<0>Hey,<1>I'm Jérémie from Belgium and I've been working on CommaFeed in my free time for over 10 years now. Thanks for taking an interest in helping me continue supporting CommaFeed." msgstr "<0>こんにちは、<1>私はベルギーのジェレミーです。私はこれまで 10 年以上、CommaFeed のオープンソースプロジェクトを無料で開発してきました。あなたの関心に感謝します。" - #: src/pages/auth/LoginPage.tsx msgid "<0>Need an account?<1>Sign up!" msgstr "<0>アカウントが必要ですか?<1>サインアップ!" @@ -322,6 +321,10 @@ msgstr "入力" msgid "Enter your current password to change profile settings" msgstr "プロファイル設定を変更するには、現在のパスワードを入力してください" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "エントリーヘッダー" @@ -609,6 +612,10 @@ msgstr "モバイル" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "モバイルでは、画面の下部にアクションボタンを表示します" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "おっと!" @@ -799,7 +806,6 @@ msgstr "Shift" msgid "Show CommaFeed's own context menu on right click" msgstr "右クリックでCommaFeedのコンテキストメニューを表示する" - #: src/components/settings/DisplaySettings.tsx msgid "Show confirmation when marking all entries as read" msgstr "すべてのエントリーを既読にするときに確認を表示する" diff --git a/commafeed-client/src/locales/ko/messages.po b/commafeed-client/src/locales/ko/messages.po index 4ff2ad37..d90bb367 100644 --- a/commafeed-client/src/locales/ko/messages.po +++ b/commafeed-client/src/locales/ko/messages.po @@ -321,6 +321,10 @@ msgstr "입력" msgid "Enter your current password to change profile settings" msgstr "프로필 설정을 변경하려면 현재 비밀번호를 입력하세요." +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "앗!" diff --git a/commafeed-client/src/locales/ms/messages.po b/commafeed-client/src/locales/ms/messages.po index 8a9d6a88..9bfba9c4 100644 --- a/commafeed-client/src/locales/ms/messages.po +++ b/commafeed-client/src/locales/ms/messages.po @@ -321,6 +321,10 @@ msgstr "Masuk" msgid "Enter your current password to change profile settings" msgstr "Masukkan kata laluan semasa anda untuk menukar tetapan profil" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Aduh!" diff --git a/commafeed-client/src/locales/nb/messages.po b/commafeed-client/src/locales/nb/messages.po index 2afa72d4..40dfc087 100644 --- a/commafeed-client/src/locales/nb/messages.po +++ b/commafeed-client/src/locales/nb/messages.po @@ -321,6 +321,10 @@ msgstr "" msgid "Enter your current password to change profile settings" msgstr "Skriv inn ditt nåværende passord for å endre profilinnstillinger" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Beklager!" diff --git a/commafeed-client/src/locales/nl/messages.po b/commafeed-client/src/locales/nl/messages.po index 887e202b..90c3a8c1 100644 --- a/commafeed-client/src/locales/nl/messages.po +++ b/commafeed-client/src/locales/nl/messages.po @@ -321,6 +321,10 @@ msgstr "" msgid "Enter your current password to change profile settings" msgstr "Voer uw huidige wachtwoord in om de profielinstellingen te wijzigen" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Oeps!" diff --git a/commafeed-client/src/locales/nn/messages.po b/commafeed-client/src/locales/nn/messages.po index cf645984..09903109 100644 --- a/commafeed-client/src/locales/nn/messages.po +++ b/commafeed-client/src/locales/nn/messages.po @@ -321,6 +321,10 @@ msgstr "" msgid "Enter your current password to change profile settings" msgstr "Skriv inn ditt nåværende passord for å endre profilinnstillinger" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Beklager!" diff --git a/commafeed-client/src/locales/pl/messages.po b/commafeed-client/src/locales/pl/messages.po index fcff2a3c..9b031773 100644 --- a/commafeed-client/src/locales/pl/messages.po +++ b/commafeed-client/src/locales/pl/messages.po @@ -321,6 +321,10 @@ msgstr "Wprowadź" msgid "Enter your current password to change profile settings" msgstr "Wprowadź swoje aktualne hasło, aby zmienić ustawienia profilu" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Ups!" diff --git a/commafeed-client/src/locales/pt/messages.po b/commafeed-client/src/locales/pt/messages.po index de98672d..0bcd8dec 100644 --- a/commafeed-client/src/locales/pt/messages.po +++ b/commafeed-client/src/locales/pt/messages.po @@ -321,6 +321,10 @@ msgstr "Entrar" msgid "Enter your current password to change profile settings" msgstr "Digite sua senha atual para alterar as configurações do perfil" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Opa!" diff --git a/commafeed-client/src/locales/ru/messages.po b/commafeed-client/src/locales/ru/messages.po index 77e16d70..4879fb16 100644 --- a/commafeed-client/src/locales/ru/messages.po +++ b/commafeed-client/src/locales/ru/messages.po @@ -321,6 +321,10 @@ msgstr "Ввод" msgid "Enter your current password to change profile settings" msgstr "Введите текущий пароль, чтобы изменить настройки профиля." +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "На мобильных устройствах отображать кнопки действий в нижней части экрана" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Ой!" diff --git a/commafeed-client/src/locales/sk/messages.po b/commafeed-client/src/locales/sk/messages.po index 0ea4eb22..8971f969 100644 --- a/commafeed-client/src/locales/sk/messages.po +++ b/commafeed-client/src/locales/sk/messages.po @@ -321,6 +321,10 @@ msgstr "Vstúpte" msgid "Enter your current password to change profile settings" msgstr "Ak chcete zmeniť nastavenia profilu, zadajte svoje aktuálne heslo" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Ojoj!" diff --git a/commafeed-client/src/locales/sv/messages.po b/commafeed-client/src/locales/sv/messages.po index 96c3a1bb..b6800fdf 100644 --- a/commafeed-client/src/locales/sv/messages.po +++ b/commafeed-client/src/locales/sv/messages.po @@ -321,6 +321,10 @@ msgstr "" msgid "Enter your current password to change profile settings" msgstr "Ange ditt nuvarande lösenord för att ändra profilinställningar" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Hoppsan!" diff --git a/commafeed-client/src/locales/tr/messages.po b/commafeed-client/src/locales/tr/messages.po index 30ffb3c5..14f9f691 100644 --- a/commafeed-client/src/locales/tr/messages.po +++ b/commafeed-client/src/locales/tr/messages.po @@ -321,6 +321,10 @@ msgstr "Girin" msgid "Enter your current password to change profile settings" msgstr "Profil ayarlarını değiştirmek için mevcut şifrenizi girin" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "" @@ -608,6 +612,10 @@ msgstr "" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "Hata!" diff --git a/commafeed-client/src/locales/zh/messages.po b/commafeed-client/src/locales/zh/messages.po index b48f7839..6f36e1a8 100644 --- a/commafeed-client/src/locales/zh/messages.po +++ b/commafeed-client/src/locales/zh/messages.po @@ -321,6 +321,10 @@ msgstr "回车" msgid "Enter your current password to change profile settings" msgstr "输入您当前的密码以更改配置文件设置" +#: src/components/settings/DisplaySettings.tsx +msgid "Entries to keep above the selected entry when scrolling" +msgstr "" + #: src/components/settings/DisplaySettings.tsx msgid "Entry headers" msgstr "条目头部" @@ -608,6 +612,10 @@ msgstr "移动端" msgid "On mobile, show action buttons at the bottom of the screen" msgstr "在移动端,显示屏幕底部的操作按钮" +#: src/components/settings/DisplaySettings.tsx +msgid "Only applies to compact, cozy and detailed modes" +msgstr "" + #: src/pages/ErrorPage.tsx msgid "Oops!" msgstr "哎呀!" diff --git a/commafeed-client/vite.config.ts b/commafeed-client/vite.config.ts index 4abeea41..34083d42 100644 --- a/commafeed-client/vite.config.ts +++ b/commafeed-client/vite.config.ts @@ -49,4 +49,7 @@ export default defineConfig(env => ({ }, }, }, + test: { + environment: "jsdom", + }, })) diff --git a/commafeed-server/src/main/java/com/commafeed/backend/model/UserSettings.java b/commafeed-server/src/main/java/com/commafeed/backend/model/UserSettings.java index 86010960..a333c6e4 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/model/UserSettings.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/model/UserSettings.java @@ -78,6 +78,8 @@ public class UserSettings extends AbstractModel { @Column(nullable = false) private ScrollMode scrollMode; + private int entriesToKeepOnTopWhenScrolling; + @Enumerated(EnumType.STRING) @Column(nullable = false) private IconDisplayMode starIconDisplayMode; diff --git a/commafeed-server/src/main/java/com/commafeed/frontend/model/Settings.java b/commafeed-server/src/main/java/com/commafeed/frontend/model/Settings.java index 66a915a1..8a35c9ac 100644 --- a/commafeed-server/src/main/java/com/commafeed/frontend/model/Settings.java +++ b/commafeed-server/src/main/java/com/commafeed/frontend/model/Settings.java @@ -49,6 +49,9 @@ public class Settings implements Serializable { requiredMode = RequiredMode.REQUIRED) private String scrollMode; + @Schema(description = "number of entries to keep above the selected entry when scrolling", requiredMode = RequiredMode.REQUIRED) + private int entriesToKeepOnTopWhenScrolling; + @Schema( description = "whether to show the star icon in the header of entries", allowableValues = "always,never,on_desktop,on_mobile", diff --git a/commafeed-server/src/main/java/com/commafeed/frontend/resource/UserREST.java b/commafeed-server/src/main/java/com/commafeed/frontend/resource/UserREST.java index 1144f325..5c11d22a 100644 --- a/commafeed-server/src/main/java/com/commafeed/frontend/resource/UserREST.java +++ b/commafeed-server/src/main/java/com/commafeed/frontend/resource/UserREST.java @@ -114,6 +114,7 @@ public class UserREST { s.setLanguage(settings.getLanguage()); s.setScrollSpeed(settings.getScrollSpeed()); s.setScrollMode(settings.getScrollMode().name()); + s.setEntriesToKeepOnTopWhenScrolling(settings.getEntriesToKeepOnTopWhenScrolling()); s.setStarIconDisplayMode(settings.getStarIconDisplayMode().name()); s.setExternalLinkIconDisplayMode(settings.getExternalLinkIconDisplayMode().name()); s.setMarkAllAsReadConfirmation(settings.isMarkAllAsReadConfirmation()); @@ -139,6 +140,7 @@ public class UserREST { s.setLanguage("en"); s.setScrollSpeed(400); s.setScrollMode(ScrollMode.if_needed.name()); + s.setEntriesToKeepOnTopWhenScrolling(0); s.setStarIconDisplayMode(IconDisplayMode.on_desktop.name()); s.setExternalLinkIconDisplayMode(IconDisplayMode.on_desktop.name()); s.setMarkAllAsReadConfirmation(true); @@ -172,6 +174,7 @@ public class UserREST { s.setLanguage(settings.getLanguage()); s.setScrollSpeed(settings.getScrollSpeed()); s.setScrollMode(ScrollMode.valueOf(settings.getScrollMode())); + s.setEntriesToKeepOnTopWhenScrolling(settings.getEntriesToKeepOnTopWhenScrolling()); s.setStarIconDisplayMode(IconDisplayMode.valueOf(settings.getStarIconDisplayMode())); s.setExternalLinkIconDisplayMode(IconDisplayMode.valueOf(settings.getExternalLinkIconDisplayMode())); s.setMarkAllAsReadConfirmation(settings.isMarkAllAsReadConfirmation()); diff --git a/commafeed-server/src/main/resources/changelogs/db.changelog-5.2.xml b/commafeed-server/src/main/resources/changelogs/db.changelog-5.2.xml new file mode 100644 index 00000000..339a746b --- /dev/null +++ b/commafeed-server/src/main/resources/changelogs/db.changelog-5.2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/commafeed-server/src/main/resources/migrations.xml b/commafeed-server/src/main/resources/migrations.xml index 6e9fb88e..9c74cf79 100644 --- a/commafeed-server/src/main/resources/migrations.xml +++ b/commafeed-server/src/main/resources/migrations.xml @@ -32,5 +32,6 @@ + \ No newline at end of file