diff --git a/plugins/clean-view-luna/src/Settings.tsx b/plugins/clean-view-luna/src/Settings.tsx new file mode 100644 index 0000000..7298b20 --- /dev/null +++ b/plugins/clean-view-luna/src/Settings.tsx @@ -0,0 +1,40 @@ +import { ReactiveStore } from "@luna/core"; +import { LunaSettings, LunaSwitchSetting } from "@luna/ui"; +import React from "react"; + +export const settings = await ReactiveStore.getPluginStorage("CleanView", { + hideUIEnabled: false, + playerBarVisible: true, +}); + +export const Settings = () => { + const [hideUIEnabled, setHideUIEnabled] = React.useState(settings.hideUIEnabled); + const [playerBarVisible, setPlayerBarVisible] = React.useState(settings.playerBarVisible); + + return ( + + { + console.log("Hide UI Feature:", checked ? "enabled" : "disabled"); + setHideUIEnabled((settings.hideUIEnabled = checked)); + }} + /> + { + console.log("Player Bar Visibility:", checked ? "visible" : "hidden"); + setPlayerBarVisible((settings.playerBarVisible = checked)); + // Update styles immediately when setting changes + if ((window as any).updateCleanViewStyles) { + (window as any).updateCleanViewStyles(); + } + }} + /> + + ); +}; \ No newline at end of file diff --git a/plugins/clean-view-luna/src/index.ts b/plugins/clean-view-luna/src/index.ts index 3701005..7057710 100644 --- a/plugins/clean-view-luna/src/index.ts +++ b/plugins/clean-view-luna/src/index.ts @@ -1,7 +1,8 @@ import { LunaUnload, Tracer, ftch } from "@luna/core"; +import { settings, Settings } from "./Settings"; export const { trace } = Tracer("[Clean View]"); - +export { Settings }; // clean up resources export const unloads = new Set(); @@ -25,6 +26,15 @@ const styles = ` margin: -40px; } +/* Only prevent specific text elements in player bar from being affected by margin adjustments */ +[data-test="footer-player"] [class*="_trackTitle"], +[data-test="footer-player"] [class*="_artistName"], +[data-test="footer-player"] [class*="_trackInfo"], +[data-test="footer-player"] [class*="_trackContainer"] { + margin-top: 0 !important; + transform: none !important; +} + [class*="_nowPlayingContainer"] { padding-left: 6%; padding-top: 20px !important; @@ -153,13 +163,54 @@ const updateButtonStates = function(): void { const unhideButton = document.querySelector('.unhide-ui-button') as HTMLElement; if (hideButton) { - hideButton.style.display = isCleanView ? 'none' : 'flex'; + hideButton.style.display = (settings.hideUIEnabled && !isCleanView) ? 'flex' : 'none'; } if (unhideButton) { - unhideButton.style.display = isCleanView ? 'flex' : 'none'; + unhideButton.style.display = (settings.hideUIEnabled && isCleanView) ? 'flex' : 'none'; } }; +// Function to get dynamic styles including player bar visibility +const getDynamicStyles = function(): string { + let dynamicStyles = styles; + + // Add player bar hiding with hover reveal if setting is disabled + if (!settings.playerBarVisible) { + dynamicStyles += ` +/* Hide player bar when setting is disabled, but show on hover */ +[data-test="footer-player"] { + opacity: 0 !important; + transition: opacity 0.3s ease-in-out !important; + pointer-events: auto !important; +} + +[data-test="footer-player"]:hover { + opacity: 1 !important; +} + +/* Also show player bar when hovering over the bottom area */ +body:has([data-test="footer-player"]:hover) [data-test="footer-player"], +body [data-test="footer-player"]:hover { + opacity: 1 !important; +} +`; + } + + return dynamicStyles; +}; + +// Function to update styles when settings change +const updateCleanViewStyles = function(): void { + if (isCleanView && appliedStyle) { + // Remove old styles and apply new ones with updated settings + appliedStyle.remove(); + appliedStyle = ApplyCSS(getDynamicStyles()); + } +}; + +// Make this function available globally so Settings can call it +(window as any).updateCleanViewStyles = updateCleanViewStyles; + const toggleCleanView = function(): void { if (isCleanView) { if (appliedStyle) { @@ -167,7 +218,7 @@ const toggleCleanView = function(): void { appliedStyle = null; } } else { - appliedStyle = ApplyCSS(styles); + appliedStyle = ApplyCSS(getDynamicStyles()); // Debug: Log bottom-left buttons to help identify selectors //debugBottomLeftButtons(); } @@ -194,6 +245,9 @@ const toggleCleanView = function(): void { const createHideUIButton = function(): void { setTimeout(() => { + // Only create button if Hide UI is enabled in settings + if (!settings.hideUIEnabled) return; + // Look for the fullscreen button's parent container const fullscreenButton = document.querySelector('[data-test="request-fullscreen"]'); if (!fullscreenButton || !fullscreenButton.parentElement) { @@ -254,6 +308,9 @@ const createHideUIButton = function(): void { const createUnhideUIButton = function(): void { setTimeout(() => { + // Only create button if Hide UI is enabled in settings + if (!settings.hideUIEnabled) return; + // Check if our button already exists if (document.querySelector('.unhide-ui-button')) return; @@ -358,14 +415,17 @@ function observeTrackTitle(): void { // Also observe for the buttons to appear so we can add our buttons function observeForButtons(): void { const observer = new MutationObserver(() => { - const fullscreenButton = document.querySelector('[data-test="request-fullscreen"]'); - if (fullscreenButton && !document.querySelector('.hide-ui-button')) { - createHideUIButton(); - } - - // Create unhide button if it doesn't exist - if (!document.querySelector('.unhide-ui-button')) { - createUnhideUIButton(); + // Only observe for buttons if Hide UI is enabled + if (settings.hideUIEnabled) { + const fullscreenButton = document.querySelector('[data-test="request-fullscreen"]'); + if (fullscreenButton && !document.querySelector('.hide-ui-button')) { + createHideUIButton(); + } + + // Create unhide button if it doesn't exist + if (!document.querySelector('.unhide-ui-button')) { + createUnhideUIButton(); + } } }); diff --git a/plugins/oled-theme-luna/src/Settings.tsx b/plugins/oled-theme-luna/src/Settings.tsx new file mode 100644 index 0000000..bb7fae6 --- /dev/null +++ b/plugins/oled-theme-luna/src/Settings.tsx @@ -0,0 +1,44 @@ +import { ReactiveStore } from "@luna/core"; +import { LunaSettings, LunaSwitchSetting } from "@luna/ui"; +import React from "react"; + +export const settings = await ReactiveStore.getPluginStorage("OLEDTheme", { + qualityColorMatchedSeekBar: true, + oledFriendlyButtons: true, +}); + +export const Settings = () => { + const [qualityColorMatchedSeekBar, setQualityColorMatchedSeekBar] = React.useState(settings.qualityColorMatchedSeekBar); + const [oledFriendlyButtons, setOledFriendlyButtons] = React.useState(settings.oledFriendlyButtons); + + return ( + + { + console.log("Quality Color Matched Seek Bar:", checked ? "enabled" : "disabled"); + setQualityColorMatchedSeekBar((settings.qualityColorMatchedSeekBar = checked)); + // Update styles immediately when setting changes + if ((window as any).updateOLEDThemeStyles) { + (window as any).updateOLEDThemeStyles(); + } + }} + /> + { + console.log("OLED Friendly Buttons:", checked ? "enabled" : "disabled"); + setOledFriendlyButtons((settings.oledFriendlyButtons = checked)); + // Update styles immediately when setting changes + if ((window as any).updateOLEDThemeStyles) { + (window as any).updateOLEDThemeStyles(); + } + }} + /> + + ); +}; \ No newline at end of file diff --git a/plugins/oled-theme-luna/src/index.css b/plugins/oled-theme-luna/src/index.css deleted file mode 100644 index 5bd6c99..0000000 --- a/plugins/oled-theme-luna/src/index.css +++ /dev/null @@ -1,301 +0,0 @@ -/* -{ - "name": "Abyss Neptune", - "author": "@itzzexcel", - "description": "Abyss Neptune: ShadowX Theme from Spicetify to TIDAL (17/Jan/2025)" -} -*/ - -::-webkit-scrollbar { - display: none; -} - -:root { - --wave-color-solid-accent-fill: white; - --wave-color-solid-rainbow-yellow-fill: white; - --wave-color-solid-contrast-fill: white; - --wave-color-solid-base-brighter: black; - --wave-text-body-medium: white !important; - --track-vibrant-color: white !important; - --wave-color-opacity-contrast-fill-ultra-thin: #fffafa1a !important; - --wave-color-solid-rainbow-yellow-darkest: #fffafa1a !important; - --wave-color-solid-accent-dark: rgb(128, 128, 128); -} - -/* Credits to https://github.com/surfbryce for the fonts */ -@font-face { - font-family: "AbyssFont"; - font-weight: 400; - src: url("https://excel.lexploits.top/extra/tidal/LyricsRegular.woff2") format("woff2"); -} - -@font-face { - font-family: "AbyssFont"; - font-weight: 500; - src: url("https://excel.lexploits.top/extra/tidal/LyricsMedium.woff2") format("woff2"); -} - -@font-face { - font-family: "AbyssFont"; - font-weight: 600; - src: url("https://excel.lexploits.top/extra/tidal/LyricsSemibold.woff2") format("woff2"); -} - -@font-face { - font-family: "AbyssFont"; - font-weight: 700; - src: url("https://excel.lexploits.top/extra/tidal/LyricsBold.woff2") format("woff2"); -} - -[class^="followingButton"], -[title="Unfollow"], -[title="Follow"], -[title="Unfollow"]>span, -[title="Follow"]>span { - background-color: var(--wave-color-solid-rainbow-yellow-fill) !important; - color: var(--wave-color-solid-base-brighter); -} - -[class^="_wave-badge-color-max"] { - color: black !important; - background-color: var(--wave-color-solid-accent-fill); - border-radius: 3px; -} - -[data-test="main-layout-sidebar-wrapper"] { - border-right: rgb(25, 25, 25) 1px solid; -} - -[class^="_wave-badge"] { - background-color: var(--wave-color-solid-accent-fill); - border-radius: 4px; - color: black; -} - -[class^="_progressBarWrapper"] { - color: var(--wave-color-solid-accent-fill) !important; -} - -[class^="_sidebarItem"]>span { - color: var(--wave-color-solid-accent-dark); -} - -[data-test="main-layout-header"] { - border-left: 0 !important; -} - -[class^="_sidebarItem"]:hover span { - color: var(--wave-color-solid-contrast-fill); -} - -[class^="_sidebarItem"] [class^="active"]>span { - color: var(--wave-color-solid-accent-dark) !important; -} - -[class^="_active"] { - color: var(--wave-color-solid-accent-fill) !important; -} - -[class^="ReactVirtualized__Grid"] { - border-radius: 10px; - margin: 5px; -} - -[data-test="media-table"]>div>div>div { - border: 1px solid rgb(25, 25, 25) !important; -} - -[class^="ReactVirtualized__Grid__innerScrollContainer"] { - border: none; - margin: 5px; -} - -[class^="button"]>span { - color: black; -} - -[class^="_explicitBadge"] { - color: var(--wave-color-solid-accent-fill); -} - -[class^="viewAllButton"] { - border-radius: 4px; - display: grid; - place-items: center; -} - -[data-test="current-media-imagery"] { - border: 0 !important; - margin: none; -} - -[class^="_imageBorder"] { - display: none; -} - -[class^="_headerButtons"]>button, -[class^="_headerButtons"]>button>span, -[data-test="toggle-picture-in-picture"] { - background-color: var(--wave-color-solid-accent-fill) !important; - color: black; -} - -[class^="_container"]>[class^="_navigationArrows"] { - color: black; - background-color: var(--wave-color-solid-accent-fill) !important; - border-radius: 4px; -} - -[class^="_buttons"]>button>span { - color: black !important; -} - -[class^="_container"]>button { - border: 0px none; -} - - -[data-test="feed-sidebar"] { - margin-top: 10px; -} - -[data-test="footer-player"] { - width: calc(100% - 20px); - bottom: 10px; - left: 10px; - border: 1px solid rgb(25, 25, 25); - border-radius: 4px !important; - position: absolute !important; -} - -[class^="_tooltipContainer"]>button { - background-color: var(--wave-color-solid-accent-fill); - color: black; -} - -[class^="_tooltipContainer"]>button:hover { - background-color: lightgray !important; -} - -[class^="_tableRow"]:hover>*, -[data-test-is-playing="true"]>* { - color: var(--wave-color-solid-accent-fill) !important; -} - -[class^="_tableRow"]>*, -[data-test-is-playing="false"]>* { - color: lightgray !important; -} - -[class*="coverColumn"] { - padding-left: 5px !important; -} - -[class^="actionList"] { - background-color: transparent; - margin: 0px; - border-radius: 5px; -} - -button[data-test="request-fullscreen"], -button[data-test="close-now-playing"], -button[data-test="play-all"], -button[data-test="shuffle-all"] { - color: black; - background-color: var(--wave-color-solid-accent-fill); - border-radius: 12px; -} - -button[data-test="request-fullscreen"]:hover, -button[data-test="close-now-playing"]:hover { - color: black; - background-color: lightgray !important; -} - -.neptune-switch-checkbox:checked+.neptune-switch { - background-color: rgba(255, 255, 255, 0.1); -} - -[data-test="navigation-arrows"]>button { - background-color: var(--wave-color-solid-accent-fill) !important; - color: black !important; - border-radius: 5px; -} - -[data-test="navigation-arrows"]>button:disabled { - background-color: lightgray !important; - opacity: 1; -} - -[data-test="main-layout-header"], -[data-test="feed-sidebar"], -[data-test="stream-metadata"], -[data-test="footer-player"] { - background-color: rgba(0, 0, 0, 0.8) !important; - backdrop-filter: blur(10px); - border: 1px solid var(--wave-color-opacity-contrast-fill-ultra-thin) !important; -} - -[data-wave-color=textUrl] { - color: var(--wave-color-solid-accent-fill); -} - -[class^="_smallHeader"] { - margin-top: 7.5px; -} - -[data-test="play-all"]>div>*, -[data-test="shuffle-all"]>div>*, -[data-test="play-all"], -[data-test="shuffle-all"] { - color: var(--wave-color-solid-accent-fill) !important; - background-color: transparent !important; -} - -[class^="__NEPTUNE_PAGE"], -[data-test="main"] { - margin-top: 35px; -} - -[data-test="button-desktop-release-notes"], -[data-test="button-release-notes"] { - background-color: white; -} - -[data-test="button-desktop-release-notes"]:hover, -[data-test="button-release-notes"]:hover { - background-color: lightgray !important; - transition: none !important; -} - -#playQueueSidebar { - top: 50px !important; - border: 1px solid var(--wave-color-opacity-contrast-fill-ultra-thin); - margin: 2px; - margin-right: -14px !important; - background-color: rgba(0, 0, 0, 0.8) !important; - backdrop-filter: blur(10px); -} - -[class^="_bottomGradient"] { - visibility: hidden; -} - -[data-test="settings-page"] { - padding-bottom: 60px !important; -} - -[data-test="query-suggestions"], -[data-test="recent-searches-container"] { - background-color: rgba(0, 0, 0, 0.6); - backdrop-filter: blur(10px); -} - -[data-test="contextmenu"] { - border: 1px solid var(--wave-color-opacity-contrast-fill-ultra-thin) !important; -} - -[class^="_dataContainer_"]::before { - background-image: var(--img); - filter: blur(10px) brightness(0.4); -} \ No newline at end of file diff --git a/plugins/oled-theme-luna/src/index.ts b/plugins/oled-theme-luna/src/index.ts index 9c3573b..6f2f45a 100644 --- a/plugins/oled-theme-luna/src/index.ts +++ b/plugins/oled-theme-luna/src/index.ts @@ -1,6 +1,8 @@ import { LunaUnload, Tracer, ftch } from "@luna/core"; +import { settings, Settings } from "./Settings"; export const { trace } = Tracer("[OLED Theme]"); +export { Settings }; const themeUrl = "https://raw.githubusercontent.com/ItzzExcel/neptune-projects/refs/heads/main/themes/black-neptune-theme.css"; @@ -8,23 +10,110 @@ const themeUrl = "https://raw.githubusercontent.com/ItzzExcel/neptune-projects/r // clean up resources export const unloads = new Set(); +let originalStyle: string | null = null; +let appliedStyleElement: HTMLStyleElement | null = null; + +// Function to apply theme styles based on current settings +const applyThemeStyles = function(): void { + if (!originalStyle) return; + + // Remove existing style element if it exists + if (appliedStyleElement && appliedStyleElement.parentNode) { + appliedStyleElement.parentNode.removeChild(appliedStyleElement); + } + + let modifiedStyle = originalStyle; + + // Remove SeekBar coloring if Quality Color Matched Seek Bar is enabled + if (settings.qualityColorMatchedSeekBar) { + modifiedStyle = modifiedStyle.replace(/\[class\^="_progressBarWrapper"\]\s*\{[^}]*\}/g, ''); + trace.msg.log("OLED theme applied with SeekBar coloring removed"); + } else { + trace.msg.log("OLED theme applied with original SeekBar coloring"); + } + + // Remove button styling if OLED Friendly Buttons is enabled + if (settings.oledFriendlyButtons) { + // First, let's debug what we're working with + const originalRuleCount = (modifiedStyle.match(/\{[^}]*\}/g) || []).length; + trace.msg.log(`Original CSS has ${originalRuleCount} rules`); + + // Split CSS into individual rules and filter out button-related ones + const cssRules = modifiedStyle.split('}').filter(rule => rule.trim()); + const filteredRules = cssRules.filter(rule => { + const lowerRule = rule.toLowerCase(); + + // Check if this rule might affect buttons + const isButtonRule = + // Direct button selectors + lowerRule.includes('button') || + lowerRule.includes('[role="button"]') || + lowerRule.includes('[type="button"]') || + lowerRule.includes('[type="submit"]') || + lowerRule.includes('[type="reset"]') || + // Class-based button selectors + lowerRule.includes('btn') || + lowerRule.includes('_button') || + lowerRule.includes('-button') || + lowerRule.includes('button-') || + lowerRule.includes('button_') || + // Common button-related classes + lowerRule.includes('clickable') || + lowerRule.includes('action') || + lowerRule.includes('control') || + lowerRule.includes('icon') || + // Data attributes that might be buttons + lowerRule.includes('data-test') && lowerRule.includes('button') || + lowerRule.includes('aria-label') && lowerRule.includes('button') || + // Button states + lowerRule.includes(':hover') && (lowerRule.includes('button') || lowerRule.includes('btn')) || + lowerRule.includes(':focus') && (lowerRule.includes('button') || lowerRule.includes('btn')) || + lowerRule.includes(':active') && (lowerRule.includes('button') || lowerRule.includes('btn')) || + // Cursor pointer (often used on buttons) + lowerRule.includes('cursor') && lowerRule.includes('pointer') || + // Any class containing button-like patterns + /\[class[^=]*=["'][^"']*button/i.test(rule) || + /\[class[^=]*=["'][^"']*btn/i.test(rule) || + /\[class[^=]*=["'][^"']*click/i.test(rule) || + /\[class[^=]*=["'][^"']*action/i.test(rule) || + /\[class[^=]*=["'][^"']*control/i.test(rule); + + // Return true to keep the rule (i.e., if it's NOT a button rule) + return !isButtonRule; + }); + + modifiedStyle = filteredRules.join('} ') + (filteredRules.length > 0 ? '}' : ''); + + const filteredRuleCount = (modifiedStyle.match(/\{[^}]*\}/g) || []).length; + const removedRuleCount = originalRuleCount - filteredRuleCount; + trace.msg.log(`OLED Friendly Buttons enabled: Removed ${removedRuleCount} button-related CSS rules, ${filteredRuleCount} rules remaining`); + } else { + trace.msg.log("OLED Friendly Buttons disabled: Button styling preserved from original theme"); + } + + appliedStyleElement = document.createElement("style"); + appliedStyleElement.type = "text/css"; + appliedStyleElement.textContent = modifiedStyle; + document.head.appendChild(appliedStyleElement); +}; + +// Make this function available globally so Settings can call it +(window as any).updateOLEDThemeStyles = applyThemeStyles; + // Added Top-level async since Luna plugins are modules <3 -const style = await ftch.text(themeUrl).catch((error: Error) => { +originalStyle = await ftch.text(themeUrl).catch((error: Error) => { trace.msg.err(`Failed to fetch theme CSS: ${error.message}`); return null; }); // Apply the OLED theme if CSS was fetched successfully -if (style) { - const styleElement = document.createElement("style"); - styleElement.type = "text/css"; - styleElement.textContent = style; - document.head.appendChild(styleElement); +if (originalStyle) { + applyThemeStyles(); // Add cleanup to unloads unloads.add(() => { - if (styleElement.parentNode) { - styleElement.parentNode.removeChild(styleElement); + if (appliedStyleElement && appliedStyleElement.parentNode) { + appliedStyleElement.parentNode.removeChild(appliedStyleElement); } }); } \ No newline at end of file diff --git a/plugins/oled-theme-luna/src/types.d.ts b/plugins/oled-theme-luna/src/types.d.ts deleted file mode 100644 index 72a2c2c..0000000 --- a/plugins/oled-theme-luna/src/types.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module "*.css" { - const content: string; - export default content; -} \ No newline at end of file