Files
custum-hyprpanel/src/style/index.ts
Jas Singh 8cf5806766 Minor: Refactor the code-base for better organization and compartmentalization. (#934)
* Clean up unused code

* Fix media player formatting issue for labels with new line characteres.

* Refactor the media player handlers into a class.

* More code cleanup and organize shared weather utils into distinct classes.

* Flatten some nesting.

* Move weather manager in dedicated class and build HTTP Utility class for Rest API calling.

* Remove logs

* Rebase master merge

* Reorg code (WIP)

* More reorg

* Delete utility scripts

* Reorg options

* Finish moving all options over

* Fix typescript issues

* Update options imports to default

* missed update

* Screw barrel files honestly, work of the devil.

* Only initialize power profiles if power-profiles-daemon is running.

* Fix window positioning and weather service naming

* style dir

* More organization

* Restructure types to be closer to their source

* Remove lib types and constants

* Update basic weather object to be saner with extensibility.

* Service updates

* Fix initialization strategy for services.

* Fix Config Manager to only emit changed objects and added missing temp converters.

* Update storage service to handle unit changes.

* Added cpu temp sensor auto-discovery

* Added missing JSDocs to services

* remove unused

* Migrate to network service.

* Fix network password issue.

* Move out password input into helper

* Rename password mask constant to be less double-negativey.

* Dropdown menu rename

* Added a component to edit JSON in the settings dialog (rough/WIP)

* Align settings

* Add and style JSON Editor.

* Adjust padding

* perf(shortcuts):  avoid unnecessary polling when shortcuts are disabled

Stops the recording poller when shortcuts are disabled, preventing redundant polling and reducing resource usage.

* Fix types and return value if shortcut not enabled.

* Move the swww daemon checking process outside of the wallpaper service into a dedicated deamon lifecyle processor.

* Add more string formatters and use title case for weather status (as it was).

* Fix startup errors.

* Rgba fix

* Remove zod from dependencies

---------

Co-authored-by: KernelDiego <gonzalezdiego.contact@gmail.com>
2025-05-26 19:45:11 -07:00

221 lines
7.4 KiB
TypeScript

import { MatugenColors } from '../lib/options/types';
import { initializeTrackers } from './optionsTrackers';
import { readFile, writeFile } from 'astal/file';
import { App } from 'astal/gtk3';
import { initializeHotReload } from './utils/hotReload';
import { Opt } from 'src/lib/options';
import { SystemUtilities } from 'src/core/system/SystemUtilities';
import options from 'src/configuration';
import { MatugenService } from 'src/services/matugen';
import { isHexColor } from 'src/lib/validation/colors';
const matugenService = MatugenService.getInstance();
/**
* Central manager for theme styling throughout the application
* Handles the transformation of theme options into compiled CSS
*/
class ThemeStyleManager {
/**
* Orchestrates the full theme regeneration process
* Falls back to standard theme if Matugen is unavailable
*/
public async applyCss(): Promise<void> {
if (!SystemUtilities.checkDependencies('sass')) return;
try {
const variables = await this._generateThemeVariables();
await this._compileSass(variables);
this._applyCss();
} catch (error) {
console.error(error);
}
}
/**
* Decides whether to use Matugen-generated colors or standard theme variables
* Controls the main theming strategy based on user configuration
*
* @returns An array of SCSS variable declarations
*/
private async _generateThemeVariables(): Promise<string[]> {
const useMatugen = options.theme.matugen.get();
if (!useMatugen) {
return this._extractStandardVariables();
}
const matugenColors = await matugenService.generateMatugenColors();
if (!matugenColors) {
return this._extractStandardVariables();
}
return this._extractMatugenizedVariables(matugenColors);
}
/**
* Recursively processes theme objects to generate SCSS variables
* Handles nested properties by creating properly namespaced variable names
*
* @returns An array of SCSS variable declarations using standard theme values
*/
private _extractStandardVariables(): string[] {
const cssVariables: string[] = [];
const optArray = options.toArray();
for (const opt of optArray) {
const currentPath = opt.id;
if (!currentPath.startsWith('theme.')) {
continue;
}
const variableName = this._buildCssVariableName(currentPath);
const variable = this._buildCssVariable(variableName, opt);
cssVariables.push(variable);
}
return cssVariables;
}
/**
* Alternative variable extraction when using Matugen's color generation
* Processes all theme options and applies Matugen's palette where appropriate
*
* @param matugenColors - Color palette generated by Matugen service
* @returns An array of SCSS variable declarations with Matugen colors applied
*/
private async _extractMatugenizedVariables(matugenColors: MatugenColors): Promise<string[]> {
try {
const result: string[] = [];
const optArray = options.toArray();
for (const opt of optArray) {
const currentPath = opt.id;
if (!currentPath.startsWith('theme.')) {
continue;
}
const optionValue = opt.get();
const variableName = this._buildCssVariableName(currentPath);
if (!isHexColor(optionValue)) {
result.push(`$${variableName}: ${optionValue};`);
continue;
}
const defaultThemeValue = opt.initial;
if (!isHexColor(defaultThemeValue)) {
continue;
}
const matugenColor = matugenService.getMatugenHex(defaultThemeValue, matugenColors);
result.push(`$${variableName}: ${matugenColor};`);
}
return result;
} catch (error) {
console.error(error);
return [];
}
}
/**
* Handles object properties that have values needing transformation
* Creates properly formatted SCSS variable declarations
*
* @param variableName - CSS-friendly variable name
* @param property - Option object containing the property value
* @returns Formatted SCSS variable declaration
*/
private _buildCssVariable(variableName: string, property: Opt): string {
const propertyValue = property.get();
return `$${variableName}: ${propertyValue};`;
}
/**
* Transforms dotted paths into hyphenated CSS variable names
* Strips the "theme." prefix for cleaner variable naming
*
* @param path - Dot-notation path of an option (e.g., "theme.background.primary")
* @returns CSS-friendly variable name (e.g., "background-primary")
*/
private _buildCssVariableName(path: string): string {
return path.replace('theme.', '').split('.').join('-');
}
/**
* Executes the SCSS compilation process with generated variables
* Combines main SCSS with custom variables and module styles
*
* @param themeVariables - Array of SCSS variable declarations for user customization options
*
* File paths used in compilation:
* - themeVariablesPath: Contains all user-configurable variables (theme colors, margins, borders, etc.)
* - appScssPath: The application's main SCSS entry point file
* - entryScssPath: A temporary file that combines all SCSS sources in the correct order
* - modulesScssPath: User-defined custom module styles
* - compiledCssPath: The final compiled CSS that gets used by the application
*/
private async _compileSass(themeVariables: string[]): Promise<void> {
const themeVariablesPath = `${TMP}/variables.scss`;
const appScssPath = `${SRC_DIR}/src/style/main.scss`;
const entryScssPath = `${TMP}/entry.scss`;
const modulesScssPath = `${CONFIG_DIR}/modules.scss`;
const compiledCssPath = `${TMP}/main.css`;
const scssImports = [`@import '${themeVariablesPath}';`];
writeFile(themeVariablesPath, themeVariables.join('\n'));
let combinedScss = readFile(appScssPath);
combinedScss = `${scssImports.join('\n')}\n${combinedScss}`;
const moduleCustomizations = readFile(modulesScssPath);
combinedScss = `${combinedScss}\n${moduleCustomizations}`;
writeFile(entryScssPath, combinedScss);
await SystemUtilities.bash(
`sass --load-path=${SRC_DIR}/src/style ${entryScssPath} ${compiledCssPath}`,
);
}
/**
* Loads the compiled CSS into the application
*
* @remarks
* Uses the compiled CSS file generated in _compileSass to apply styles to the application
*/
private _applyCss(): void {
const compiledCssPath = `${TMP}/main.css`;
App.apply_css(compiledCssPath, true);
}
}
const themeManager = new ThemeStyleManager();
const optionsToWatch = [
'font',
'theme',
'bar.flatButtons',
'bar.position',
'bar.battery.charging',
'bar.battery.blocks',
];
initializeTrackers(themeManager.applyCss.bind(themeManager));
initializeHotReload();
options.handler(optionsToWatch, themeManager.applyCss.bind(themeManager));
await themeManager.applyCss();
export { themeManager };