feat(big-picture): add PostCSS plugin for scoping CSS styles to the big picture component

This commit is contained in:
japa2k
2026-04-23 00:26:00 -03:00
parent 2e699871e3
commit 83d90bd7f6
4 changed files with 71 additions and 4 deletions
+12 -3
View File
@@ -1,12 +1,13 @@
import { resolve } from "path";
import react from "@vitejs/plugin-react";
import {
defineConfig,
externalizeDepsPlugin,
loadEnv,
swcPlugin,
externalizeDepsPlugin,
} from "electron-vite";
import react from "@vitejs/plugin-react";
import { resolve } from "path";
import svgr from "vite-plugin-svgr";
import { scopeBigPictureCss } from "./src/big-picture/vite-scope-big-picture-css";
export default defineConfig(({ mode }) => {
loadEnv(mode);
@@ -37,6 +38,11 @@ export default defineConfig(({ mode }) => {
input: resolve("src/big-picture/index.html"),
},
},
css: {
postcss: {
plugins: [scopeBigPictureCss()],
},
},
resolve: {
alias: {
"@locales": resolve("src/locales"),
@@ -50,6 +56,9 @@ export default defineConfig(({ mode }) => {
sourcemap: true,
},
css: {
postcss: {
plugins: [scopeBigPictureCss()],
},
preprocessorOptions: {
scss: {
api: "modern",
@@ -0,0 +1,52 @@
import type { Plugin, Rule } from "postcss";
const BIG_PICTURE_ROOT_SELECTOR = "#big-picture";
const BIG_PICTURE_PATH_FRAGMENT = "/src/big-picture/";
const ROOT_SELECTOR_ALIASES = new Set([":root", "html", "body", "#root"]);
const isBigPictureStyle = (filePath?: string): boolean => {
if (!filePath) return false;
return filePath.replaceAll("\\", "/").includes(BIG_PICTURE_PATH_FRAGMENT);
};
const shouldSkipRule = (rule: Rule): boolean => {
const parent = rule.parent;
return (
parent?.type === "atrule" &&
"name" in parent &&
parent.name.toLowerCase().endsWith("keyframes")
);
};
const scopeSelector = (selector: string): string => {
const trimmedSelector = selector.trim();
if (!trimmedSelector) return selector;
if (
trimmedSelector === BIG_PICTURE_ROOT_SELECTOR ||
trimmedSelector.startsWith(`${BIG_PICTURE_ROOT_SELECTOR} `) ||
trimmedSelector.startsWith(`${BIG_PICTURE_ROOT_SELECTOR}:`)
) {
return selector;
}
if (ROOT_SELECTOR_ALIASES.has(trimmedSelector)) {
return BIG_PICTURE_ROOT_SELECTOR;
}
return `${BIG_PICTURE_ROOT_SELECTOR} ${selector}`;
};
export const scopeBigPictureCss = (): Plugin => ({
postcssPlugin: "scope-big-picture-css",
Rule(rule) {
if (!isBigPictureStyle(rule.source?.input.file) || shouldSkipRule(rule)) {
return;
}
rule.selectors = rule.selectors.map(scopeSelector);
},
});
+6
View File
@@ -1,6 +1,7 @@
import { resolve } from "path";
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { scopeBigPictureCss } from "./vite-scope-big-picture-css";
export default defineConfig({
root: resolve(__dirname),
@@ -8,6 +9,11 @@ export default defineConfig({
outDir: resolve(__dirname, "../../dist/big-picture"),
emptyOutDir: true,
},
css: {
postcss: {
plugins: [scopeBigPictureCss()],
},
},
resolve: {
alias: {
"@shared": resolve(__dirname, "../../src/shared"),
+1 -1
View File
@@ -1,6 +1,6 @@
{
"extends": "@electron-toolkit/tsconfig/tsconfig.node.json",
"include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*", "src/locales/index.ts", "src/shared/**/*", "src/types/**/*"],
"include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*", "src/locales/index.ts", "src/shared/**/*", "src/types/**/*", "src/big-picture/vite-scope-big-picture-css.ts"],
"compilerOptions": {
"module": "ESNext",
"composite": true,