// ==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://dev.gossys.dev/other/branch/master/giteascripts // @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]; } })();