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
This commit is contained in:
commit
1ed638c38b
5 changed files with 260 additions and 0 deletions
22
README.md
Normal file
22
README.md
Normal file
|
|
@ -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))
|
||||
|
||||
---
|
||||
|
||||
|  |  |
|
||||
|-------------------------|------------------------|
|
||||
|  | |
|
||||
238
main.user.js
Normal file
238
main.user.js
Normal file
|
|
@ -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: `
|
||||
<div
|
||||
class="__${APP_ID}__tweaksModal__container ui dimmer"
|
||||
:class="{ 'active': isActive }"
|
||||
@click="event => isActive = event.target !== event.currentTarget"
|
||||
><div
|
||||
class="ui small modal active"
|
||||
>
|
||||
<div class="__${APP_ID}__tweaksModal__header header">
|
||||
<span>${APP_NAME}</span>
|
||||
<button
|
||||
class="__${APP_ID}__tweaksModal__header__close"
|
||||
@click.stop="isActive = false"
|
||||
><i
|
||||
class="bx bx-x"
|
||||
></i></button>
|
||||
</div>
|
||||
<form class="__${APP_ID}__tweaksModal__form content">
|
||||
<div
|
||||
class="ui checkbox"
|
||||
><input
|
||||
v-model="settings.isFixCommentButtonsAlignment"
|
||||
type="checkbox"
|
||||
><label>Fix comment buttons alignment</label></div>
|
||||
<div
|
||||
class="ui checkbox"
|
||||
><input
|
||||
v-model="settings.isNavbarSticky"
|
||||
type="checkbox"
|
||||
><label>Sticky navbar</label></div>
|
||||
<div
|
||||
class="ui checkbox"
|
||||
><input
|
||||
v-model="settings.isCodeViewScrollable"
|
||||
type="checkbox"
|
||||
><label>Scrollable code view</label></div>
|
||||
<div
|
||||
class="ui checkbox"
|
||||
><input
|
||||
v-model="settings.isFixIssuesTabConsistency"
|
||||
type="checkbox"
|
||||
><label>Fix issues tab consistency</label></div>
|
||||
<div
|
||||
class="ui checkbox"
|
||||
><input
|
||||
v-model="settings.isRestoreFeatureRichMarkdownEditor"
|
||||
type="checkbox"
|
||||
><label>Restore feature-rich Markdown editor</label></div>
|
||||
<div
|
||||
class="ui checkbox"
|
||||
><input
|
||||
v-model="settings.isSortAdminUsersByNewestByDefault"
|
||||
type="checkbox"
|
||||
><label>Sort <code class="inline-code-block">/admin/users</code> by newest by default</label></div>
|
||||
</form>
|
||||
</div></div>
|
||||
`
|
||||
});
|
||||
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 = `<i class='bx bxs-extension'></i>`;
|
||||
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];
|
||||
}
|
||||
})();
|
||||
BIN
screenshot1.png
Normal file
BIN
screenshot1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
BIN
screenshot2.png
Normal file
BIN
screenshot2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
screenshot3.webp
Normal file
BIN
screenshot3.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Loading…
Add table
Add a link
Reference in a new issue