// ==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: `
isActive = event.target !== event.currentTarget"
>
`
});
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];
}
})();