Hide progress and streak tracking so Dicoding stays focused on learning navigation.
// ==UserScript==
// @name Dicoding Focus Mode - Calm Module Sidebar
// @namespace local.dicoding.focus
// @version 1.2.0
// @description Hide progress and streak tracking so Dicoding stays focused on learning navigation.
// @author Thesedays
// @license MIT
// @match https://www.dicoding.com/academies/*/tutorials/*
// @match https://dicoding.com/academies/*/tutorials/*
// @run-at document-start
// @grant none
// ==/UserScript==
(function () {
'use strict';
const STYLE_ID = 'dicoding-focus-mode-style';
const ROOT_SELECTOR = '#modules-list';
const PROGRESS_HEADER_SELECTOR = `${ROOT_SELECTOR} .sidebar-navigation-v3__content__header`;
const CATEGORY_ITEM_SELECTOR = `${ROOT_SELECTOR} .modules-category-list__list-item`;
const MODULE_LIST_SELECTOR = `${ROOT_SELECTOR} .module-list__list`;
const ITEM_STATUS_SELECTOR = `${ROOT_SELECTOR} .module-list__list-item__status`;
const STREAK_SELECTOR = '.nav-streak, #streakDropdown, .streak-dropdown-menu';
function addStyle() {
if (document.getElementById(STYLE_ID)) {
return;
}
const styleTarget = document.head || document.documentElement;
if (!styleTarget) {
return;
}
const style = document.createElement('style');
style.id = STYLE_ID;
style.textContent = `
${ROOT_SELECTOR} .modules-list__progress,
${ROOT_SELECTOR} .modules-list__progress + div,
${CATEGORY_ITEM_SELECTOR} > div:last-child:not(:first-child),
${ITEM_STATUS_SELECTOR},
${STREAK_SELECTOR} {
display: none !important;
}
${CATEGORY_ITEM_SELECTOR} > div:first-child {
width: 100% !important;
}
${ROOT_SELECTOR} .module-list__list-item__link {
margin-left: 0 !important;
}
`;
styleTarget.appendChild(style);
}
function hideProgressElements() {
document.querySelectorAll(PROGRESS_HEADER_SELECTOR).forEach((header) => {
if (header.querySelector('.modules-list__progress, [role="progressbar"]')) {
header.remove();
}
});
document.querySelectorAll(`${ROOT_SELECTOR} [role="progressbar"]`).forEach((progressbar) => {
progressbar.remove();
});
document.querySelectorAll(ITEM_STATUS_SELECTOR).forEach((status) => {
status.remove();
});
document.querySelectorAll(`${CATEGORY_ITEM_SELECTOR} > div:last-child:not(:first-child)`).forEach((status) => {
status.remove();
});
}
function hideStreakElements() {
document.querySelectorAll('#streakDropdown').forEach((streakDropdown) => {
const streakContainer = streakDropdown.closest('.nav-streak, .nav-item, li');
if (streakContainer) {
streakContainer.remove();
return;
}
streakDropdown.remove();
});
document.querySelectorAll('.streak-dropdown-menu').forEach((streakMenu) => {
streakMenu.remove();
});
}
function escapeSelectorValue(value) {
if (window.CSS && typeof window.CSS.escape === 'function') {
return window.CSS.escape(value);
}
return value.replace(/["\\]/g, '\\$&');
}
function getCategoryToggle(moduleList) {
if (!moduleList.id) {
return null;
}
return document.querySelector(`${ROOT_SELECTOR} [data-target="#${escapeSelectorValue(moduleList.id)}"]`);
}
function setModuleListExpanded(moduleList, shouldExpand) {
const toggle = getCategoryToggle(moduleList);
moduleList.classList.toggle('show', shouldExpand);
if (toggle) {
toggle.classList.toggle('collapsed', !shouldExpand);
toggle.setAttribute('aria-expanded', String(shouldExpand));
}
}
function applyAccordion() {
const root = document.querySelector(ROOT_SELECTOR);
if (!root || root.dataset.dicodingFocusAccordionReady === 'true') {
return;
}
const moduleLists = Array.from(root.querySelectorAll(MODULE_LIST_SELECTOR));
if (moduleLists.length === 0) {
return;
}
const activeModuleList = moduleLists.find((moduleList) => moduleList.querySelector('.js-current-module'))
|| root.querySelector(`${MODULE_LIST_SELECTOR}.show`);
if (!activeModuleList) {
return;
}
moduleLists.forEach((moduleList) => {
setModuleListExpanded(moduleList, moduleList === activeModuleList);
});
root.addEventListener('click', (event) => {
const toggle = event.target.closest('[data-toggle="collapse"][data-target^="#module-"]');
if (!toggle || !root.contains(toggle)) {
return;
}
const targetSelector = toggle.getAttribute('data-target');
if (!targetSelector) {
return;
}
const target = root.querySelector(targetSelector);
if (!target) {
return;
}
const shouldExpand = !target.classList.contains('show');
window.setTimeout(() => {
Array.from(root.querySelectorAll(MODULE_LIST_SELECTOR)).forEach((moduleList) => {
setModuleListExpanded(moduleList, moduleList === target && shouldExpand);
});
}, 0);
});
root.dataset.dicodingFocusAccordionReady = 'true';
}
function run() {
addStyle();
hideProgressElements();
hideStreakElements();
applyAccordion();
}
run();
function startObserver() {
const observerTarget = document.documentElement || document;
const observer = new MutationObserver(run);
observer.observe(observerTarget, {
childList: true,
subtree: true,
});
}
startObserver();
})();