commit 1ed638c38b02a2f9bfa9df2ad8c47e63174451b4 Author: Коробцев Виталий Сергеевич Date: Mon Jun 9 10:53:40 2025 +0500 Please enter the commit message for your changes. Lines starting with '' will be ignored, and an empty message aborts the commit. On branch main Initial commit Changes to be committed: new file: README.md new file: main.user.js new file: screenshot1.png new file: screenshot2.png new file: screenshot3.webp diff --git a/README.md b/README.md new file mode 100644 index 0000000..8896dff --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +[← Homepage](../README.md) + +# Enhancements for Forgejo + +| [Install](../../../../raw/branch/master/enhancementsForForgejo/main.user.js) | +|------------------------------------------------------------------------------| + +## Features + +- ~~Fix alphabetical files ordering~~ ([`forgejo/forgejo@codeberg.org#317`](https://codeberg.org/forgejo/forgejo/issues/317), fixed by [`forgejo/forgejo@codeberg.org#2522`](https://codeberg.org/forgejo/forgejo/pulls/2522)) +- Fix comment buttons alignment ([`forgejo/forgejo@codeberg.org#560`](https://codeberg.org/forgejo/forgejo/issues/560)) +- Sticky navbar ([`forgejo/forgejo@codeberg.org#1318`](https://codeberg.org/forgejo/forgejo/issues/1318)) +- Scrollable code view +- Fix issues tab consistency ([`forgejo/forgejo@codeberg.org#365`](https://codeberg.org/forgejo/forgejo/issues/365)) +- Restore feature-rich Markdown editor ([`forgejo/forgejo@codeberg.org#3604`](https://codeberg.org/forgejo/forgejo/issues/3604)) +- Sort `/admin/users` by newest by default ([`forgejo/forgejo@codeberg.org#2574`](https://codeberg.org/forgejo/forgejo/issues/2574)) + +--- + +| ![](./screenshot1.png) | ![](./screenshot2.png) | +|-------------------------|------------------------| +| ![](./screenshot3.webp) | | \ No newline at end of file diff --git a/main.user.js b/main.user.js new file mode 100644 index 0000000..4f7d729 --- /dev/null +++ b/main.user.js @@ -0,0 +1,238 @@ +// ==UserScript== +// @match https://*/* +// @name Enhancements for Forgejo +// @description Enhancements for Forgejo +// @grant GM.getValue +// @grant GM.setValue +// @version 0.2.1 +// @author KaKi87 +// @license MIT +// @namespace https://git.kaki87.net/KaKi87/userscripts/src/branch/master/enhancementsForForgejo +// @require https://cdn.jsdelivr.net/npm/vue@3.3.4/dist/vue.global.prod.js +// ==/UserScript== + +const + APP_ID = 'enhancementsForForgejo', + APP_NAME = 'Enhancements for Forgejo'; + +(async () => { + if(!document.querySelector('[href$="/explore/repos"]')) return; + unsafeWindow.Vue = Vue; + let + tweaksModalAppMountedPromiseResolve, + setTweakModalActive, + getSettings; + const + tweaksModalElement = document.createElement('div'), + tweaksModalAppMountedPromise = new Promise(resolve => tweaksModalAppMountedPromiseResolve = resolve), + tweaksModalApp = Vue.createApp({ + data: () => ({ + isActive: false, + settings: { + isFixCommentButtonsAlignment: true, + isNavbarSticky: false, + isCodeViewScrollable: true, + isFixIssuesTabConsistency: true, + isRestoreFeatureRichMarkdownEditor: true, + isSortAdminUsersByNewestByDefault: true + } + }), + methods: { + refreshSettings: async function(){ + const settings = await GM.getValue('settings'); + if(settings) + Object.assign(this.settings, settings); + }, + applySettings: function(){ + document.body.classList.toggle(`__${APP_ID}--isFixCommentButtonsAlignment`, this.settings.isFixCommentButtonsAlignment); + document.body.classList.toggle(`__${APP_ID}--isNavbarSticky`, this.settings.isNavbarSticky); + document.body.classList.toggle(`__${APP_ID}--isCodeViewScrollable`, this.settings.isCodeViewScrollable); + } + }, + watch: { + isActive: async function(isActive, wasActive){ + document.body.classList.toggle('dimmable', isActive); + document.body.classList.toggle('dimmed', isActive); + if(!wasActive && isActive) + await this.refreshSettings(); + }, + settings: { + deep: true, + handler: async function(){ + await GM.setValue('settings', this.settings); + this.applySettings(); + } + } + }, + mounted: async function(){ + await this.refreshSettings(); + setTweakModalActive = isActive => this.isActive = isActive; + getSettings = () => this.settings; + tweaksModalAppMountedPromiseResolve(); + this.applySettings(); + }, + template: ` +
+ ` + }); + tweaksModalElement.setAttribute('class', `__${APP_ID}__tweaksModal`); + await Promise.all([ + tweaksModalApp.mount(tweaksModalElement), + tweaksModalAppMountedPromise + ]); + document.body.append(tweaksModalElement); + for(const userMenuNotificationsElement of document.querySelectorAll('[href="/notifications"]')){ + const userMenuTweaksElement = document.createElement(userMenuNotificationsElement.tagName); + userMenuTweaksElement.style.setProperty('--width', `${userMenuNotificationsElement.offsetWidth}px`); + userMenuTweaksElement.style.setProperty('--height', `${userMenuNotificationsElement.offsetHeight}px`); + userMenuTweaksElement.setAttribute('class', `__${APP_ID}__tweaksMenu ${userMenuNotificationsElement.className}`); + userMenuTweaksElement.setAttribute('data-tooltip-content', APP_NAME); + userMenuTweaksElement.setAttribute('href', '#'); + userMenuTweaksElement.innerHTML = ``; + userMenuTweaksElement.addEventListener( + 'click', + event => { + event.preventDefault(); + setTweakModalActive(true); + } + ); + userMenuNotificationsElement.parentElement.insertBefore(userMenuTweaksElement, userMenuNotificationsElement); + } + { + const issuesTabElement = document.querySelector(`[href="${window.location.pathname}/issues"]`); + if(issuesTabElement && getSettings().isFixIssuesTabConsistency) + issuesTabElement.setAttribute('href', `${issuesTabElement.getAttribute('href')}?state=open`); + } + if(getSettings().isRestoreFeatureRichMarkdownEditor){ + localStorage.setItem('markdown-editor-default', 'easymde'); + localStorage.setItem('markdown-editor-wiki', 'easymde'); + } + if(window.location.pathname.startsWith('/admin') && getSettings().isSortAdminUsersByNewestByDefault) + document.querySelector('[href="/admin/users"]').setAttribute('href', '/admin/users?sort=newest'); + document.documentElement.style.setProperty( + `--${APP_ID}-navbar-height`, + `${document.querySelector('#navbar').offsetHeight}px` + ); + document.head.append(Object.assign( + document.createElement('link'), + { 'rel': 'stylesheet', 'href': 'https://cdn.jsdelivr.net/npm/boxicons@2.1.4/css/boxicons.min.css' } + )); + { + const styles = new CSSStyleSheet(); + // language=CSS + await styles.replace(` + .__${APP_ID}__tweaksMenu { + padding: 0 !important; + justify-content: center; + width: var(--width); + height: var(--height); + font-size: 1.25rem; + color: inherit; + } + .__${APP_ID}__tweaksModal__container { + position: fixed !important; + } + .__${APP_ID}__tweaksModal__header { + display: flex !important; + justify-content: space-between; + } + .__${APP_ID}__tweaksModal__header__close { + border: none; + background: none; + padding: 0; + font-size: 1.5rem; + cursor: pointer; + } + .__${APP_ID}__tweaksModal__form { + display: flex !important; + flex-direction: column; + row-gap: 0.5rem; + } + .__${APP_ID}__tweaksModal__form .checkbox label { + user-select: initial; + } + .__${APP_ID}--isFixCommentButtonsAlignment div:has(> #status-button) { + display: flex; + justify-content: flex-end; + column-gap: 0.5rem; + } + .__${APP_ID}--isFixCommentButtonsAlignment #status-button { + margin-bottom: 0; + display: flex; + align-items: center; + justify-content: center; + } + .__${APP_ID}--isNavbarSticky [role="main"] { + padding-top: var(--${APP_ID}-navbar-height); + } + .__${APP_ID}--isNavbarSticky #navbar { + position: fixed; + width: 100%; + z-index: 1; + } + .__${APP_ID}--isCodeViewScrollable .code-view, + .__${APP_ID}--isCodeViewScrollable .code-block { + overflow: auto; + } + .__${APP_ID}--isCodeViewScrollable .code-view .code-inner, + .__${APP_ID}--isCodeViewScrollable .code-block .chroma { + white-space: pre; + } + `); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, styles]; + } +})(); \ No newline at end of file diff --git a/screenshot1.png b/screenshot1.png new file mode 100644 index 0000000..68cb7d7 Binary files /dev/null and b/screenshot1.png differ diff --git a/screenshot2.png b/screenshot2.png new file mode 100644 index 0000000..2221167 Binary files /dev/null and b/screenshot2.png differ diff --git a/screenshot3.webp b/screenshot3.webp new file mode 100644 index 0000000..dc4123a Binary files /dev/null and b/screenshot3.webp differ