diff --git a/Dribbblish/color.ini b/Dribbblish/color.ini index bdf4d1b..718537a 100644 --- a/Dribbblish/color.ini +++ b/Dribbblish/color.ini @@ -3,13 +3,13 @@ text = FFFFFF subtext = F0F0F0 sidebar-text = FFFFFF main = 000000 -sidebar = 1ed760 +sidebar = 24b558 player = 000000 card = 000000 shadow = 202020 selected-row = 797979 -button = 1ed760 -button-active = 1ed760 +button = 24b558 +button-active = 24b558 button-disabled = 535353 tab-active = 166632 notification = 1db954 @@ -116,7 +116,7 @@ sidebar = 6F3C89 player = 0A0E14 card = 0A0E14 shadow = 3a2645 -selected-row = EBDFFF +selected-row = 645275 button = c76af6 button-active = 6F3C89 button-disabled = 535353 @@ -207,10 +207,10 @@ player = 161616 card = 161616 shadow = 252525 selected-row = 202020 -button = 0064e1 -button-active = 0064e1 +button = 3281ea +button-active = 0284e8 button-disabled = 303030 -tab-active = 0064e1 -notification = 0064e1 +tab-active = ebbcba +notification = 3281ea notification-error = b10c0c misc = 252525 diff --git a/Dribbblish/theme.js b/Dribbblish/theme.js index bcca18e..66b7949 100644 --- a/Dribbblish/theme.js +++ b/Dribbblish/theme.js @@ -7,20 +7,17 @@ function waitForElement(els, func, timeout = 100) { } } +let DribbblishShared = {}; + // back shadow waitForElement([".Root__top-container"], ([topContainer]) => { const shadow = document.createElement("div"); shadow.id = "dribbblish-back-shadow"; topContainer.prepend(shadow); - - // check if element has two children - const mainNav = topContainer.querySelector(".main-navBar-mainNav"); - if (mainNav && mainNav.childElementCount === 1) { - document.documentElement.classList.add("legacy-nav"); - legacy(); - } }); +// Spicetify.Platform.ConnectAPI.state.connectionStatus; + // add fade effect on playlist/folder list waitForElement([".main-navBar-mainNav .os-viewport.os-viewport-native-scrollbars-invisible"], ([scrollNode]) => { scrollNode.setAttribute("fade", "bottom"); @@ -35,6 +32,8 @@ waitForElement([".main-navBar-mainNav .os-viewport.os-viewport-native-scrollbars }); }); +let version; + (function Dribbblish() { // dynamic playback time tooltip const progBar = document.querySelector(".playback-bar"); @@ -45,6 +44,18 @@ waitForElement([".main-navBar-mainNav .os-viewport.os-viewport-native-scrollbars return; } + version = Spicetify.Platform.PlatformData.event_sender_context_information.client_version_int; + + if (version < 121200000) { + document.documentElement.classList.add("legacy"); + legacy(); + } else if (version >= 121200000 && version < 121400000) { + document.documentElement.classList.add("legacy-gridChange"); + legacy(); + } else if (version >= 121400000) { + document.documentElement.classList.add("ylx"); + } + const tooltip = document.createElement("div"); tooltip.className = "prog-tooltip"; progBar.append(tooltip); @@ -64,30 +75,173 @@ waitForElement([".main-navBar-mainNav .os-viewport.os-viewport-native-scrollbars } Spicetify.Player.addEventListener("onprogress", updateProgTime); updateProgTime({ data: Spicetify.Player.getProgress() }); + + waitForElement( + [`.main-yourLibraryX-libraryRootlist`, `.main-rootlist-wrapper > div:nth-child(2)`, "li.main-yourLibraryX-listItem"], + ([rootlist, listElement]) => { + listElement.classList.add("dribs-playlist-list"); + + const loadFolderImages = items => { + if (!items) items = listElement.children; + for (const item of items) { + let id = item.querySelector("div > div:nth-child(2)").id; + if (!id.includes("folder")) continue; + + id = id.split(":")[4]; + console.log(id); + + const base64 = localStorage.getItem("dribbblish:folder-image:" + id); + + const img_container = item.querySelector(".HeaderSideArea .x-entityImage-imageContainer"); + + if (!base64) { + if (img_container.querySelector("img")) img_container.children[0].remove(); + continue; + } + + img_container.children[0].remove(); + const img = document.createElement("img"); + img.classList.add("main-image-image", "x-entityImage-image", "main-image-loaded"); + img.src = base64; + img_container.append(img); + } + }; + + const getNewEls = mutationsList => { + for (const mutation of mutationsList) { + if (mutation.type === "childList") { + if (!mutation.addedNodes.length) continue; + loadFolderImages(mutation.addedNodes); + } + } + }; + + const refresh = mutationsList => { + console.log("refresh"); + for (const mutation of mutationsList) { + if (mutation.type === "attributes" && mutation.attributeName === "class") { + loadFolderImages(listElement.children); + } + } + }; + + loadFolderImages(); + + new MutationObserver(getNewEls).observe(listElement, { childList: true }); + new MutationObserver(refresh).observe(rootlist, { attributes: true, attributeFilter: ["class"] }); + + DribbblishShared.loadFolderImages = loadFolderImages; + } + ); + + // filepicker for custom folder images + const filePickerForm = document.createElement("form"); + filePickerForm.setAttribute("aria-hidden", true); + filePickerForm.innerHTML = ''; + document.body.appendChild(filePickerForm); + /** @type {HTMLInputElement} */ + const filePickerInput = filePickerForm.childNodes[0]; + filePickerInput.accept = ["image/jpeg", "image/apng", "image/avif", "image/gif", "image/png", "image/svg+xml", "image/webp"].join(","); + + filePickerInput.onchange = () => { + if (!filePickerInput.files.length) return; + + const file = filePickerInput.files[0]; + const reader = new FileReader(); + reader.onload = event => { + const result = event.target.result; + const id = Spicetify.URI.from(filePickerInput.uri).id; + try { + localStorage.setItem("dribbblish:folder-image:" + id, result); + } catch { + Spicetify.showNotification("File too large"); + } + if (version < 121200000) { + DribbblishShared.loadPlaylistImage?.call(); + } else { + DribbblishShared.loadFolderImages?.call(); + } + }; + reader.readAsDataURL(file); + }; + + // context menu items for custom folder images + new Spicetify.ContextMenu.Item( + "Remove folder image", + ([uri]) => { + const id = Spicetify.URI.from(uri).id; + localStorage.removeItem("dribbblish:folder-image:" + id); + if (version < 121200000) { + DribbblishShared.loadPlaylistImage?.call(); + } else { + DribbblishShared.loadFolderImages?.call(); + } + }, + ([uri]) => Spicetify.URI.isFolder(uri), + "x" + ).register(); + new Spicetify.ContextMenu.Item( + "Choose folder image", + ([uri]) => { + filePickerInput.uri = uri; + filePickerForm.reset(); + filePickerInput.click(); + }, + ([uri]) => Spicetify.URI.isFolder(uri), + "edit" + ).register(); })(); // LEGACY NAVBAR ONLY - function legacy() { if (!Spicetify.Platform) { setTimeout(legacy, 300); return; } - let DribbblishShared = {}; - // allow resizing of the navbar - waitForElement([".Root__nav-bar .LayoutResizer__resize-bar"], ([resizer]) => { - console.log(resizer); + waitForElement([".Root__nav-bar .LayoutResizer__input"], ([resizer]) => { const observer = new MutationObserver(updateVariable); - observer.observe(resizer, { attributes: true, attributeFilter: ["class"] }); + observer.observe(resizer, { attributes: true, attributeFilter: ["value"] }); function updateVariable() { - if (resizer.classList.contains("LayoutResizer__resize-bar-east")) { - document.documentElement.style.setProperty("--left-sidebar-width", "72px"); + let value = resizer.value; + if (value < 121) { + value = 72; document.documentElement.classList.add("left-sidebar-collapsed"); } else { document.documentElement.classList.remove("left-sidebar-collapsed"); } + document.documentElement.style.setProperty("--nav-bar-width", value + "px"); + } + updateVariable(); + }); + + // allow resizing of the buddy feed + waitForElement([".Root__right-sidebar .LayoutResizer__input"], ([resizer]) => { + const observer = new MutationObserver(updateVariable); + observer.observe(resizer, { attributes: true, attributeFilter: ["value"] }); + function updateVariable() { + let value = resizer.value; + let min_value = version < 121200000 ? 321 : 281; + if (value < min_value) { + value = 72; + document.documentElement.classList.add("buddyFeed-hide-text"); + } else { + document.documentElement.classList.remove("buddyFeed-hide-text"); + } + } + updateVariable(); + }); + + waitForElement([".main-nowPlayingBar-container"], ([nowPlayingBar]) => { + const observer = new MutationObserver(updateVariable); + observer.observe(nowPlayingBar, { childList: true }); + function updateVariable() { + if (nowPlayingBar.childElementCount === 2) { + document.documentElement.classList.add("connected"); + } else { + document.documentElement.classList.remove("connected"); + } } updateVariable(); }); @@ -150,53 +304,4 @@ function legacy() { new MutationObserver(loadPlaylistImage).observe(listElem, { childList: true }); }); - - // filepicker for custom folder images - const filePickerForm = document.createElement("form"); - filePickerForm.setAttribute("aria-hidden", true); - filePickerForm.innerHTML = ''; - document.body.appendChild(filePickerForm); - /** @type {HTMLInputElement} */ - const filePickerInput = filePickerForm.childNodes[0]; - filePickerInput.accept = ["image/jpeg", "image/apng", "image/avif", "image/gif", "image/png", "image/svg+xml", "image/webp"].join(","); - - filePickerInput.onchange = () => { - if (!filePickerInput.files.length) return; - - const file = filePickerInput.files[0]; - const reader = new FileReader(); - reader.onload = event => { - const result = event.target.result; - const id = Spicetify.URI.from(filePickerInput.uri).id; - try { - localStorage.setItem("dribbblish:folder-image:" + id, result); - } catch { - Spicetify.showNotification("File too large"); - } - DribbblishShared.loadPlaylistImage?.call(); - }; - reader.readAsDataURL(file); - }; - - // context menu items for custom folder images - new Spicetify.ContextMenu.Item( - "Remove folder image", - ([uri]) => { - const id = Spicetify.URI.from(uri).id; - localStorage.removeItem("dribbblish:folder-image:" + id); - DribbblishShared.loadPlaylistImage?.call(); - }, - ([uri]) => Spicetify.URI.isFolder(uri), - "x" - ).register(); - new Spicetify.ContextMenu.Item( - "Choose folder image", - ([uri]) => { - filePickerInput.uri = uri; - filePickerForm.reset(); - filePickerInput.click(); - }, - ([uri]) => Spicetify.URI.isFolder(uri), - "edit" - ).register(); } diff --git a/Dribbblish/user.css b/Dribbblish/user.css index e94b7d5..5860be5 100644 --- a/Dribbblish/user.css +++ b/Dribbblish/user.css @@ -3,6 +3,8 @@ --bar-cover-art-size: 40px; --scrollbar-vertical-size: 10px; --scrollbar-horizontal-size: 10px; + --bar-height: 90px; + --main-gap: 10px; } @font-face { @@ -61,18 +63,18 @@ body { grid-area: main-view !important; } -.Root__right-sidebar { - padding-left: 8px; - grid-area: right-sidebar !important; +.legacy .Root__top-container:not(:has(> .Root__right-sidebar)) { + padding-right: var(--main-gap); } + +.ylx .Root__top-container:not(:has(> .Root__right-sidebar > aside)) { + padding-right: var(--main-gap); +} + .Root__right-sidebar:not(:has(> aside)) { padding-left: 0; } -.Root__right-sidebar > aside { - border-radius: var(--corner-radius) !important; - box-shadow: 0 0 10px 3px #0000003b; -} .Root__nav-bar { grid-area: left-sidebar !important; } @@ -395,6 +397,25 @@ li > div::after { transition: none; } +/* right sidebar text */ +.Root__right-sidebar { + --text-base: var(--spice-sidebar-text); + --background-tinted-base: var(--spice-tab-active); +} + +.Root__right-sidebar a, +.Root__right-sidebar .main-trackInfo-artists a, +.artist-artistOnTour-timeAndVenue.artist-artistOnTour-condensed, +.Root__right-sidebar .main-nowPlayingView-creditsSource, +.Root__right-sidebar .main-nowPlayingView-playNextButton, +.Root__right-sidebar .main-nowPlayingView-playNext { + color: var(--spice-sidebar-text); +} + +.main-nowPlayingView-content { + --text-subdued: var(--spice-sidebar-text); +} + /* add main backshadow */ #dribbblish-back-shadow { z-index: 5; @@ -463,45 +484,164 @@ input { background-color: var(--spice-main); } -/* LEGACY NAVBAR ONLY */ -.legacy-nav .Root__top-container { - padding: 8px; +/* v1.2.14 */ +.main-yourLibraryX-libraryContainer.main-yourLibraryX-libraryIsExpanded.main-yourLibraryX-libraryIsCollapsed, +.main-yourLibraryX-libraryRootlist.main-yourLibraryX-libraryIsExpanded:not(.main-yourLibraryX-libraryIsCollapsed) { + padding-bottom: 0; +} + +[dir="ltr"] .main-nowPlayingWidget-coverExpanded { + transform: none; +} + +.ylx .main-coverSlotExpanded-container { + bottom: calc(var(--main-gap) + 70px + 10px); + left: calc(var(--nav-bar-width) + 10px); +} +.ylx.connected .main-coverSlotExpanded-container { + bottom: calc(var(--main-gap) + 70px + 24px + 10px); +} + +/* v1.2.12 -> 1.2.13 */ +.main-buddyFeed-container { + background-color: inherit; + box-shadow: none; +} +.legacy-gridChange .main-coverSlotExpanded-container { + left: calc(var(--nav-bar-width) + 10px); +} + +/* v1.2.0 --> 1.2.11 */ +.legacy .Root__top-container { + grid-template-areas: + "left-sidebar top-bar right-sidebar" + "left-sidebar main-view right-sidebar" + "left-sidebar now-playing-bar right-sidebar" !important; +} +.Root__top-container { + padding: 10px 0; background-color: var(--spice-sidebar); } -.legacy-nav .Root__main-view { +.Root__right-sidebar { + background-color: var(--spice-sidebar); +} +.Root__main-view { background-color: var(--spice-main); } -.legacy-nav .main-rootlist-rootlistDivider { +.main-rootlist-rootlistDivider { background-color: transparent; } -.legacy-nav .main-rootlist-rootlistDividerGradient { +.main-buddyFeed-activityMetadata .main-buddyFeed-username a, +.main-buddyFeed-activityMetadata .main-buddyFeed-artistAndTrackName a, +.main-buddyFeed-activityMetadata .main-buddyFeed-usernameAndTimestamp, +.main-buddyFeed-activityMetadata .main-buddyFeed-playbackContextLink { + color: var(--spice-sidebar-text) !important; +} +.main-buddyFeed-activityMetadata .main-buddyFeed-artistAndTrackName { + color: var(--spice-sidebar-text); +} +.collection-icon, +.premiumSpotifyIcon, +.search-icon { + color: var(--spice-sidebar-text) !important; +} +.main-confirmDialog-container { + background-color: var(--spice-card); +} +.main-confirmDialog-container .TypeElement-canon-textBase { + color: var(--spice-text); +} +.main-confirmDialog-buttonContainer button span { + color: var(--spice-card); +} +.main-coverSlotExpanded-container { + position: fixed; + z-index: 2; + width: 250px; + height: 250px; + bottom: calc(var(--main-gap) + var(--bar-height) + 10px); + left: calc(var(--nav-bar-width) + 20px); +} +.connected .main-coverSlotExpanded-container { + bottom: calc(var(--main-gap) + var(--bar-height) + 24px + 10px); +} +.left-sidebar-collapsed .main-coverSlotExpanded-container { + left: 82px; +} +.main-coverSlotExpanded-container img { + border-radius: 4px; +} +.cover-art { + border-radius: 4px; +} +.left-sidebar-collapsed .Root__nav-bar { + width: 72px; +} +.left-sidebar-collapsed .main-rootlist-statusIcons { + display: none; +} +.main-navBar-navBarLinkActive { + background-color: var(--spice-tab-active); +} +.Root__nav-bar .main-rootlist-rootlist .os-scrollbar-handle { + display: none; +} +.Root__top-container:has(> .Root__top-container--right-sidebar-hidden) { + padding-right: 10px; +} +/* buddy feed w/ hidden text*/ +.buddyFeed-hide-text .Root__top-container:not(:has(> .Root__top-container--right-sidebar-hidden)) .Root__right-sidebar { + width: 72px !important; +} +.buddyFeed-hide-text .NdQkQZhcYIEcJnRdAYcQ, +.buddyFeed-hide-text .main-buddyFeed-header { + display: none; +} +.buddyFeed-hide-text .main-buddyFeed-friendActivity { + padding: 0 0 0 4px; +} +.buddyFeed-hide-text .main-buddyFeed-activityMetadata { + visibility: hidden; +} +.buddyFeed-hide-text .main-avatar-avatar > div > div > div { + display: flex; + justify-content: center; + padding-top: 7px; +} +.buddyFeed-hide-text .main-avatar-avatar, +.buddyFeed-hide-text .main-avatar-avatar div, +.buddyFeed-hide-text .main-buddyFeed-overlay { + width: 32px !important; + height: 32px !important; +} +.main-rootlist-rootlistDividerGradient { background: none; } -.legacy-nav .main-collectionLinkButton-collectionLinkButton .main-collectionLinkButton-icon, -.legacy-nav .main-collectionLinkButton-collectionLinkButton .main-collectionLinkButton-collectionLinkText { +.main-collectionLinkButton-collectionLinkButton .main-collectionLinkButton-icon, +.main-collectionLinkButton-collectionLinkButton .main-collectionLinkButton-collectionLinkText { opacity: 1; } -.legacy-nav .main-collectionLinkButton-collectionLinkButton, -.legacy-nav .main-createPlaylistButton-button { - color: var(--spice-subtext); +.main-collectionLinkButton-collectionLinkButton, +.main-createPlaylistButton-button { + color: var(--spice-sidebar-text); opacity: 1; } -.legacy-nav .main-likedSongsButton-likedSongsIcon { +.main-likedSongsButton-likedSongsIcon { background: none; } -.legacy-nav .main-likedSongsButton-likedSongsIcon > svg { +.main-likedSongsButton-likedSongsIcon > svg { height: 20px !important; width: 20px !important; } /* style added sidebar images */ -.legacy-nav .main-rootlist-rootlistItem a { +.main-rootlist-rootlistItem a { align-items: center; border-radius: 4px; display: flex; height: 56px; gap: 12px; } -.legacy-nav img.playlist-picture { +img.playlist-picture { width: 32px; height: 32px; flex: 0 0 32px; @@ -509,47 +649,99 @@ input { background-position: center; border-radius: 50%; } -.legacy-nav img.playlist-picture[src$=".svg"] { +img.playlist-picture[src$=".svg"] { width: 24px; height: 24px; border-radius: 0; } -.legacy-nav .Root__nav-bar .main-rootlist-wrapper { +.legacy .Root__nav-bar .main-rootlist-wrapper, +.legacy-gridChange .Root__nav-bar .main-rootlist-wrapper { height: fit-content !important; contain: none !important; } -.legacy-nav .main-navBar-mainNav li:has(> div > .active) { +.main-navBar-mainNav li:has(> div > .active) { background-color: var(--spice-tab-active); } -.legacy-nav .main-collectionLinkButton-selected.active { +.main-collectionLinkButton-selected.active { background-color: var(--spice-tab-active) !important; } -.legacy-nav .main-navBar-mainNav li { +.legacy .main-navBar-mainNav li, +.legacy-gridChange .main-navBar-mainNav li { background-color: transparent !important; } -.legacy-nav a.active { +/* a.active { + background-color: var(--spice-tab-active) !important; +} */ +.main-rootlist-rootlistItem:has(> .main-rootlist-rootlistItemLinkActive) { background-color: var(--spice-tab-active) !important; } -.legacy-nav .main-rootlist-rootlistItem:has(> .main-rootlist-rootlistItemLinkActive) { - background-color: var(--spice-tab-active) !important; -} -.legacy-nav .main-rootlist-rootlistItemLink { +.main-rootlist-rootlistItemLink { padding-left: 12px; } -.legacy-nav .main-rootlist-rootlistItem { +.main-rootlist-rootlistItem { margin-left: 8px; margin-right: 8px; - padding-left: 0; - padding-right: 8px; + padding-left: 0 !important; + padding-right: 8px !important; border-radius: 4px; } -.legacy-nav .dribs-playlist-list { +.dribs-playlist-list { overflow: hidden; } -.legacy-nav.left-sidebar-collapsed .main-rootlist-expandArrow { +.left-sidebar-collapsed .main-rootlist-expandArrow { display: none; } -.legacy-nav .main-navBar-navBarLink, -.legacy-nav .main-collectionLinkButton-collectionLinkButton { +.main-navBar-navBarLink, +.main-collectionLinkButton-collectionLinkButton, +.main-createPlaylistButton-button { height: 56px !important; } + +.Button-md-buttonSecondary-useBrowserDefaultFocusStyle { + border: 1px solid var(--spice-text); +} +.Button-md-buttonPrimary-useBrowserDefaultFocusStyle .ButtonInner-md { + color: var(--spice-text); +} +/* sidebar speaker icon */ +.CCeu9OfWSwIAJqA49n84 { + color: var(--spice-sidebar-text); +} +.legacy .Root__right-sidebar .os-content { + overflow-x: hidden; +} +.Root__right-sidebar .os-scrollbar-horizontal { + display: none; +} +.UyzJidwrGk3awngSGIwv, +.poz9gZKE7xqFwgk231J4, +.xWm_uA0Co4SXVxaO7wlB { + color: var(--spice-text); +} +.main-navBar-navBarLink { + color: var(--spice-sidebar-text); +} +.main-navBar-navBarLink:focus, +.main-navBar-navBarLink:hover { + color: var(--spice-sidebar-text); +} +.main-createPlaylistButton-createPlaylistIcon { + background-color: var(--spice-sidebar-text); +} +.main-rootlist-rootlistItemLink:link, +.main-rootlist-rootlistItemLink:visited { + color: var(--spice-sidebar-text) !important; +} +.main-rootlist-expandArrow { + color: var(--spice-sidebar-text); +} +.main-buddyFeed-actions button, +.main-buddyFeed-titleContainer { + color: var(--spice-sidebar-text) !important; +} +.main-tag-container { + background-color: var(--spice-subtext); +} +.main-buddyFeed-content { + height: fit-content; +}