Created
December 17, 2025 10:45
-
-
Save malys/91ce814a02787a474ca5dbe2b3701493 to your computer and use it in GitHub Desktop.
[Vikunja] minimal view #userscript #violentmonkey
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Vikunja Auto Minimal View | |
| // @namespace http://tampermonkey.net/ | |
| // @version 0.7 | |
| // @description Shows only task detail in minimal view, removing all other page elements including top bar | |
| // @author You | |
| // @match https://*/tasks/* | |
| // @grant none | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| // Check if URL has minimal=true parameter | |
| function isMinimalParam() { | |
| const urlParams = new URLSearchParams(window.location.search); | |
| return urlParams.get('minimal') === 'true'; | |
| } | |
| // Apply minimal view - show only task detail | |
| function applyMinimalView() { | |
| const container = document.querySelector('.task-view-container'); | |
| if (!container) return; | |
| // Add minimal view class | |
| container.classList.add('minimal-view'); | |
| // Hide everything except the task container | |
| const elementsToHide = [ | |
| 'aside.menu-container', | |
| 'nav.menu-container', | |
| 'header', | |
| 'header.navbar', | |
| '.navbar', | |
| '.menu-hide-button', | |
| '.menu-show-button', | |
| '.quick-actions', | |
| '.mobile-overlay', | |
| '.keyboard-shortcuts-button', | |
| '.app-container-background', | |
| '.content-auth > .menu-hide-button', | |
| '.notification', | |
| '.add-to-home-screen', | |
| '.update-notification', | |
| '.demo-mode', | |
| '.navbar-end', | |
| '.username-dropdown-trigger', | |
| '.avatar', | |
| '.navbar-brand', | |
| '.navbar-start', | |
| '.navbar-menu', | |
| '.navbar-item', | |
| '.navbar-link', | |
| '.navbar-dropdown', | |
| ]; | |
| elementsToHide.forEach(selector => { | |
| const elements = document.querySelectorAll(selector); | |
| elements.forEach(el => { | |
| el.style.display = 'none !important'; | |
| el.style.visibility = 'hidden !important'; | |
| el.style.width = '0 !important'; | |
| el.style.height = '0 !important'; | |
| el.style.overflow = 'hidden !important'; | |
| el.style.position = 'absolute !important'; | |
| el.style.left = '-9999px !important'; | |
| el.style.top = '-9999px !important'; | |
| }); | |
| }); | |
| // Hide non-essential task elements | |
| const taskSelectors = [ | |
| '.subtitle', | |
| '.checklist-summary', | |
| '.action-buttons', | |
| '.attachments', | |
| '.comments', | |
| '.related-tasks', | |
| '.detail-content .columns:not(:first-child)' | |
| ]; | |
| taskSelectors.forEach(selector => { | |
| const elements = document.querySelectorAll(selector); | |
| elements.forEach(el => el.style.display = 'none'); | |
| }); | |
| // Make task container take full viewport | |
| const taskView = document.querySelector('.task-view'); | |
| if (taskView) { | |
| taskView.style.margin = '0'; | |
| taskView.style.padding = '20px'; | |
| taskView.style.maxWidth = 'none'; | |
| taskView.style.width = '100%'; | |
| taskView.style.minHeight = '100vh'; | |
| // Remove background color to preserve theme | |
| } | |
| // Style the container to be the only visible element | |
| container.style.position = 'fixed'; | |
| container.style.top = '0'; | |
| container.style.left = '0'; | |
| container.style.width = '100vw'; | |
| container.style.height = '100vh'; | |
| container.style.margin = '0'; | |
| container.style.padding = '0'; | |
| // Remove background color to preserve theme | |
| container.style.zIndex = '999999'; | |
| container.style.overflow = 'auto'; | |
| // Hide body scroll but keep background | |
| document.body.style.margin = '0'; | |
| document.body.style.padding = '0'; | |
| // Remove background color to preserve theme | |
| document.body.style.overflow = 'hidden'; | |
| // Hide html scroll | |
| document.documentElement.style.overflow = 'hidden'; | |
| // Add toggle button | |
| addToggleButton(); | |
| const header = document.querySelector('header[aria-label="main navigation"]'); | |
| if (header) { | |
| header.style.display = 'none'; | |
| } | |
| document.querySelector( | |
| 'button.back-button.base-button--type-button' | |
| )?.style.setProperty('display', 'none', 'important'); | |
| } | |
| // Add toggle button to switch views | |
| function addToggleButton() { | |
| const heading = document.querySelector('.task-view .heading'); | |
| if (!heading || document.querySelector('#minimal-toggle')) return; | |
| const toggle = document.createElement('button'); | |
| toggle.id = 'minimal-toggle'; | |
| toggle.className = 'button'; | |
| toggle.textContent = 'Full View'; | |
| toggle.style.marginLeft = '10px'; | |
| toggle.style.fontSize = '0.8rem'; | |
| toggle.style.position = 'fixed'; | |
| toggle.style.top = '10px'; | |
| toggle.style.right = '10px'; | |
| toggle.style.zIndex = '1000000'; | |
| toggle.addEventListener('click', toggleView); | |
| document.body.appendChild(toggle); | |
| } | |
| // Toggle between minimal and full view | |
| function toggleView() { | |
| const container = document.querySelector('.task-view-container'); | |
| const toggle = document.querySelector('#minimal-toggle'); | |
| const isMinimal = container.classList.contains('minimal-view'); | |
| if (isMinimal) { | |
| // Switch to full view - restore everything | |
| container.classList.remove('minimal-view'); | |
| toggle.textContent = 'Minimal View'; | |
| // Restore all hidden elements | |
| const elementsToShow = [ | |
| 'aside.menu-container', | |
| 'nav.menu-container', | |
| 'header.navbar', | |
| '.navbar', | |
| '.menu-hide-button', | |
| '.menu-show-button', | |
| '.quick-actions', | |
| '.mobile-overlay', | |
| '.keyboard-shortcuts-button', | |
| '.app-container-background', | |
| '.notification', | |
| '.add-to-home-screen', | |
| '.update-notification', | |
| '.demo-mode', | |
| '.navbar-end', | |
| '.username-dropdown-trigger', | |
| '.avatar', | |
| '.navbar-brand', | |
| '.navbar-start', | |
| '.navbar-menu', | |
| '.navbar-item', | |
| '.navbar-link', | |
| '.navbar-dropdown' | |
| ]; | |
| elementsToShow.forEach(selector => { | |
| const elements = document.querySelectorAll(selector); | |
| elements.forEach(el => { | |
| el.style.display = ''; | |
| el.style.visibility = ''; | |
| el.style.width = ''; | |
| el.style.height = ''; | |
| el.style.overflow = ''; | |
| el.style.position = ''; | |
| el.style.left = ''; | |
| el.style.top = ''; | |
| }); | |
| }); | |
| // Restore task view styles | |
| const taskView = document.querySelector('.task-view'); | |
| if (taskView) { | |
| taskView.style.margin = ''; | |
| taskView.style.padding = ''; | |
| taskView.style.maxWidth = ''; | |
| taskView.style.width = ''; | |
| taskView.style.minHeight = ''; | |
| // Background will revert to default | |
| } | |
| // Restore container styles | |
| container.style.position = ''; | |
| container.style.top = ''; | |
| container.style.left = ''; | |
| container.style.width = ''; | |
| container.style.height = ''; | |
| container.style.margin = ''; | |
| container.style.padding = ''; | |
| // Background will revert to default | |
| container.style.zIndex = ''; | |
| container.style.overflow = ''; | |
| // Restore body styles | |
| document.body.style.margin = ''; | |
| document.body.style.padding = ''; | |
| // Background will revert to default | |
| document.body.style.overflow = ''; | |
| // Restore html scroll | |
| document.documentElement.style.overflow = ''; | |
| // Show all hidden task elements | |
| const hidden = document.querySelectorAll('.task-view [style*="display: none"]'); | |
| hidden.forEach(el => { | |
| if (!el.id || !el.id.includes('minimal-toggle')) { | |
| el.style.display = ''; | |
| } | |
| }); | |
| // Move toggle button back to heading | |
| const heading = document.querySelector('.task-view .heading'); | |
| if (heading) { | |
| toggle.style.position = ''; | |
| toggle.style.top = ''; | |
| toggle.style.right = ''; | |
| toggle.style.zIndex = ''; | |
| heading.appendChild(toggle); | |
| } | |
| } else { | |
| // Switch back to minimal view | |
| applyMinimalView(); | |
| } | |
| } | |
| // Add CSS for minimal view | |
| const style = document.createElement('style'); | |
| style.textContent = ` | |
| .minimal-view { | |
| /* Remove background to preserve theme */ | |
| } | |
| .minimal-view .task-view { | |
| padding: 20px !important; | |
| margin: 0 !important; | |
| max-width: none !important; | |
| width: 100% !important; | |
| min-height: 100vh !important; | |
| /* Remove background to preserve theme */ | |
| } | |
| /* Ensure description is visible in minimal view */ | |
| .minimal-view .details.content.description { | |
| display: block !important; | |
| } | |
| /* Hide all other elements aggressively */ | |
| body.minimal-view > *:not(.task-view-container), | |
| .minimal-view .content-auth > *:not(.task-view-container), | |
| .minimal-view .app-container > *:not(.task-view-container) { | |
| display: none !important; | |
| visibility: hidden !important; | |
| } | |
| /* Aggressively hide header and navbar elements */ | |
| .minimal-view header, | |
| .minimal-view .navbar, | |
| .minimal-view .navbar-brand, | |
| .minimal-view .navbar-start, | |
| .minimal-view .navbar-end, | |
| .minimal-view .navbar-menu, | |
| .minimal-view .navbar-item, | |
| .minimal-view .navbar-link, | |
| .minimal-view .navbar-dropdown, | |
| .minimal-view .username-dropdown-trigger, | |
| .minimal-view .avatar { | |
| display: none !important; | |
| visibility: hidden !important; | |
| position: absolute !important; | |
| left: -9999px !important; | |
| top: -9999px !important; | |
| } | |
| `; | |
| document.head.appendChild(style); | |
| // Initialize when page loads | |
| function init() { | |
| if (document.querySelector('.task-view')) { | |
| if (isMinimalParam()) { | |
| // Apply minimal view automatically | |
| setTimeout(applyMinimalView, 100); | |
| } else { | |
| // Add toggle button even without minimal parameter | |
| setTimeout(addToggleButton, 100); | |
| } | |
| } | |
| } | |
| // Use MutationObserver to handle dynamic content | |
| const observer = new MutationObserver((mutations) => { | |
| if (document.querySelector('.task-view') && !document.querySelector('#minimal-toggle')) { | |
| init(); | |
| } | |
| }); | |
| observer.observe(document.body, { | |
| childList: true, | |
| subtree: true | |
| }); | |
| // Also try immediately | |
| init(); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment