refactor: migrate some styling features to the new architecture

Again, by using StylesheetScript we also get dynamic styles for free.

Bug: twpowertools:176, twpowertools:61
Change-Id: I8c660f8b9cddaf56b3a29c8d07d48d070ee2cd34
diff --git a/src/contentScripts/communityConsole/main.js b/src/contentScripts/communityConsole/main.js
index 3e914af..d8d0ba0 100644
--- a/src/contentScripts/communityConsole/main.js
+++ b/src/contentScripts/communityConsole/main.js
@@ -1,4 +1,4 @@
-import {injectScript, injectStyles, injectStylesheet} from '../../common/contentScriptsUtils';
+import {injectScript, injectStylesheet} from '../../common/contentScriptsUtils';
 import {getOptions} from '../../common/options/optionsUtils.js';
 import XHRProxyKillSwitchHandler from '../../xhrInterceptor/killSwitchHandler.js';
 import {injectPreviousPostsLinksUnifiedProfileIfEnabled} from '../utilsCommon/unifiedProfiles.js';
@@ -125,35 +125,6 @@
   mutationObserver = new MutationObserver(mutationCallback);
   mutationObserver.observe(document.body, observerOptions);
 
-  // TODO(avm99963): The following features are not dynamic. Make them be.
-  if (options.fixedtoolbar) {
-    injectStyles(
-        'ec-bulk-actions{position: sticky; top: 0; background: var(--TWPT-primary-background, #fff); z-index: 96;}');
-  }
-
-  if (options.increasecontrast) {
-    injectStyles(
-        '.thread-summary.read:not(.checked){background: var(--TWPT-thread-read-background, #ecedee)!important;}');
-  }
-
-  if (options.stickysidebarheaders) {
-    injectStyles(
-        'material-drawer .main-header{background: var(--TWPT-drawer-background, #fff)!important; position: sticky; top: 0; z-index: 1;}');
-  }
-
-  if (options.enhancedannouncementsdot) {
-    injectStylesheet(
-        chrome.runtime.getURL('css/enhanced_announcements_dot.css'));
-  }
-
-  if (options.repositionexpandthread) {
-    injectStylesheet(chrome.runtime.getURL('css/reposition_expand_thread.css'));
-  }
-
-  if (options.imagemaxheight) {
-    injectStylesheet(chrome.runtime.getURL('css/image_max_height.css'));
-  }
-
   if (options.ccforcehidedrawer) {
     var drawer = document.querySelector('material-drawer');
     if (drawer !== null && drawer.classList.contains('mat-drawer-expanded')) {
diff --git a/src/entryPoints/communityConsole/contentScripts/main.ts b/src/entryPoints/communityConsole/contentScripts/main.ts
index 2274fd0..16bd30f 100644
--- a/src/entryPoints/communityConsole/contentScripts/main.ts
+++ b/src/entryPoints/communityConsole/contentScripts/main.ts
@@ -48,6 +48,12 @@
 import FlattenThreadsReplyBtnHandler from '../../../features/flattenThreads/presentation/nodeWatcherHandlers/replyBtn.handler';
 import FlattenThreads from '../../../features/flattenThreads/core/flattenThreads';
 import FlattenThreadsStylesScript from '../../../features/flattenThreads/presentation/scripts/styles.script';
+import FixedToolbarStylesScript from '../../../features/fixedToolbar/presentation/scripts/styles.script';
+import EnhancedAnnouncementsDotStylesScript from '../../../features/enhancedAnnouncementsDot/presentation/scripts/styles.script';
+import ImageMaxHeightStylesScript from '../../../features/imageMaxHeight/presentation/scripts/styles.script';
+import RepositionExpandThreadStylesScript from '../../../features/repositionExpandThread/presentation/scripts/styles.script';
+import StickySidebarHeadersStylesScript from '../../../features/stickySidebarHeaders/presentation/scripts/styles.script';
+import IncreaseContrastStylesScript from '../../../features/increaseContrast/presentation/scripts/styles.script';
 
 const scriptRunner = createScriptRunner();
 scriptRunner.run();
@@ -174,7 +180,13 @@
         new AutoRefreshStylesScript(),
         new CCExtraInfoInjectScript(),
         new CCExtraInfoStylesScript(),
+        new EnhancedAnnouncementsDotStylesScript(),
+        new FixedToolbarStylesScript(),
         new FlattenThreadsStylesScript(),
+        new ImageMaxHeightStylesScript(),
+        new IncreaseContrastStylesScript(),
+        new RepositionExpandThreadStylesScript(),
+        new StickySidebarHeadersStylesScript(),
         new WorkflowsImportStylesheetScript(),
 
         // Standalone scripts
diff --git a/src/features/enhancedAnnouncementsDot/presentation/scripts/styles.script.ts b/src/features/enhancedAnnouncementsDot/presentation/scripts/styles.script.ts
new file mode 100644
index 0000000..5844311
--- /dev/null
+++ b/src/features/enhancedAnnouncementsDot/presentation/scripts/styles.script.ts
@@ -0,0 +1,10 @@
+import StylesheetScript from '../../../../common/architecture/scripts/stylesheet/StylesheetScript';
+
+export default class EnhancedAnnouncementsDotStylesScript extends StylesheetScript {
+  stylesheet = 'css/enhanced_announcements_dot.css';
+  page: never;
+
+  async shouldBeInjected(): Promise<boolean> {
+    return await this.optionsProvider.isEnabled('enhancedannouncementsdot');
+  }
+}
diff --git a/src/static/css/enhanced_announcements_dot.css b/src/features/enhancedAnnouncementsDot/ui/styles.css
similarity index 100%
rename from src/static/css/enhanced_announcements_dot.css
rename to src/features/enhancedAnnouncementsDot/ui/styles.css
diff --git a/src/features/fixedToolbar/presentation/scripts/styles.script.ts b/src/features/fixedToolbar/presentation/scripts/styles.script.ts
new file mode 100644
index 0000000..29133fc
--- /dev/null
+++ b/src/features/fixedToolbar/presentation/scripts/styles.script.ts
@@ -0,0 +1,10 @@
+import StylesheetScript from '../../../../common/architecture/scripts/stylesheet/StylesheetScript';
+
+export default class FixedToolbarStylesScript extends StylesheetScript {
+  stylesheet = 'css/fixed_toolbar.css';
+  page: never;
+
+  async shouldBeInjected(): Promise<boolean> {
+    return await this.optionsProvider.isEnabled('fixedtoolbar');
+  }
+}
diff --git a/src/features/fixedToolbar/ui/styles.css b/src/features/fixedToolbar/ui/styles.css
new file mode 100644
index 0000000..c52fb30
--- /dev/null
+++ b/src/features/fixedToolbar/ui/styles.css
@@ -0,0 +1,6 @@
+ec-bulk-actions {
+  position: sticky;
+  top: 0;
+  background: var(--TWPT-primary-background, #fff);
+  z-index: 96;
+}
diff --git a/src/features/imageMaxHeight/presentation/scripts/styles.script.ts b/src/features/imageMaxHeight/presentation/scripts/styles.script.ts
new file mode 100644
index 0000000..9befaa9
--- /dev/null
+++ b/src/features/imageMaxHeight/presentation/scripts/styles.script.ts
@@ -0,0 +1,10 @@
+import StylesheetScript from '../../../../common/architecture/scripts/stylesheet/StylesheetScript';
+
+export default class ImageMaxHeightStylesScript extends StylesheetScript {
+  stylesheet = 'css/image_max_height.css';
+  page: never;
+
+  async shouldBeInjected(): Promise<boolean> {
+    return await this.optionsProvider.isEnabled('imagemaxheight');
+  }
+}
diff --git a/src/static/css/image_max_height.css b/src/features/imageMaxHeight/ui/styles.css
similarity index 100%
rename from src/static/css/image_max_height.css
rename to src/features/imageMaxHeight/ui/styles.css
diff --git a/src/features/increaseContrast/presentation/scripts/styles.script.ts b/src/features/increaseContrast/presentation/scripts/styles.script.ts
new file mode 100644
index 0000000..2ff828c
--- /dev/null
+++ b/src/features/increaseContrast/presentation/scripts/styles.script.ts
@@ -0,0 +1,10 @@
+import StylesheetScript from '../../../../common/architecture/scripts/stylesheet/StylesheetScript';
+
+export default class IncreaseContrastStylesScript extends StylesheetScript {
+  stylesheet = 'css/increase_contrast.css';
+  page: never;
+
+  async shouldBeInjected(): Promise<boolean> {
+    return await this.optionsProvider.isEnabled('increasecontrast');
+  }
+}
diff --git a/src/features/increaseContrast/ui/styles.css b/src/features/increaseContrast/ui/styles.css
new file mode 100644
index 0000000..026230e
--- /dev/null
+++ b/src/features/increaseContrast/ui/styles.css
@@ -0,0 +1,3 @@
+.thread-summary.read:not(.checked) {
+  background: var(--TWPT-thread-read-background, #ecedee) !important;
+}
diff --git a/src/features/repositionExpandThread/presentation/scripts/styles.script.ts b/src/features/repositionExpandThread/presentation/scripts/styles.script.ts
new file mode 100644
index 0000000..2d54313
--- /dev/null
+++ b/src/features/repositionExpandThread/presentation/scripts/styles.script.ts
@@ -0,0 +1,10 @@
+import StylesheetScript from '../../../../common/architecture/scripts/stylesheet/StylesheetScript';
+
+export default class RepositionExpandThreadStylesScript extends StylesheetScript {
+  stylesheet = 'css/reposition_expand_thread.css';
+  page: never;
+
+  async shouldBeInjected(): Promise<boolean> {
+    return await this.optionsProvider.isEnabled('repositionexpandthread');
+  }
+}
diff --git a/src/static/css/reposition_expand_thread.css b/src/features/repositionExpandThread/ui/styles.css
similarity index 100%
rename from src/static/css/reposition_expand_thread.css
rename to src/features/repositionExpandThread/ui/styles.css
diff --git a/src/features/stickySidebarHeaders/presentation/scripts/styles.script.ts b/src/features/stickySidebarHeaders/presentation/scripts/styles.script.ts
new file mode 100644
index 0000000..eda313e
--- /dev/null
+++ b/src/features/stickySidebarHeaders/presentation/scripts/styles.script.ts
@@ -0,0 +1,10 @@
+import StylesheetScript from '../../../../common/architecture/scripts/stylesheet/StylesheetScript';
+
+export default class StickySidebarHeadersStylesScript extends StylesheetScript {
+  stylesheet = 'css/sticky_sidebar_headers.css';
+  page: never;
+
+  async shouldBeInjected(): Promise<boolean> {
+    return await this.optionsProvider.isEnabled('stickysidebarheaders');
+  }
+}
diff --git a/src/features/stickySidebarHeaders/ui/styles.css b/src/features/stickySidebarHeaders/ui/styles.css
new file mode 100644
index 0000000..cd64b74
--- /dev/null
+++ b/src/features/stickySidebarHeaders/ui/styles.css
@@ -0,0 +1,6 @@
+material-drawer .main-header {
+  background: var(--TWPT-drawer-background, #fff) !important;
+  position: sticky;
+  top: 0;
+  z-index: 1;
+}
diff --git a/templates/manifest.gjson b/templates/manifest.gjson
index 2f3f4cf..d183096 100644
--- a/templates/manifest.gjson
+++ b/templates/manifest.gjson
@@ -119,6 +119,9 @@
         "css/thread_page_design_warning.css",
         "css/thread_toolbar.css",
         "css/flatten_threads.css",
+        "css/fixed_toolbar.css",
+        "css/increase_contrast.css",
+        "css/sticky_sidebar_headers.css",
 
         "communityConsoleMain.bundle.js.map",
         "communityConsoleStart.bundle.js.map",
diff --git a/webpack.config.js b/webpack.config.js
index 0413c5f..326ae89 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -20,26 +20,10 @@
   },
 ];
 
-const getCopyPluginsForOverridenLocales = outputPath => {
-  return localeOverrides.map(l => {
-    return new CopyWebpackPlugin({
-      patterns: [
-        {
-          from: path.join(__dirname, 'src/static/_locales/' + l.pontoonLocale),
-          to: path.join(outputPath, '_locales/' + l.webExtLocale),
-          globOptions: {
-            ignore: ['**/OWNERS', '**.md'],
-          }
-        },
-      ]
-    });
-  });
-};
-
 module.exports = (env, args) => {
   // NOTE: When adding an entry, add the corresponding source map file to
   // web_accessible_resources in //templates/manifest.gjson.
-  let entry = {
+  const entry = {
     // Content scripts
     communityConsoleMain:
         './src/entryPoints/communityConsole/contentScripts/main.ts',
@@ -78,14 +62,43 @@
 
     // Compiled Sass
     ccDarkTheme: './src/features/ccDarkTheme/core/styles/main.scss?asCSSFile',
+
+    // Background script (or service worker for MV3)
+    bg: './src/bg.js',
   };
 
-  // Background script (or service worker for MV3)
-  entry.bg = './src/bg.js';
+  // NOTE: When adding an entry, add the corresponding source map file to
+  // web_accessible_resources in //templates/manifest.gjson.
+  const styles = [
+    {
+      origin: './src/features/enhancedAnnouncementsDot/ui/styles.css',
+      destination: 'css/enhanced_announcements_dot.css',
+    },
+    {
+      origin: './src/features/fixedToolbar/ui/styles.css',
+      destination: 'css/fixed_toolbar.css',
+    },
+    {
+      origin: './src/features/imageMaxHeight/ui/styles.css',
+      destination: 'css/image_max_height.css',
+    },
+    {
+      origin: './src/features/increaseContrast/ui/styles.css',
+      destination: 'css/increase_contrast.css',
+    },
+    {
+      origin: './src/features/repositionExpandThread/ui/styles.css',
+      destination: 'css/reposition_expand_thread.css',
+    },
+    {
+      origin: './src/features/stickySidebarHeaders/ui/styles.css',
+      destination: 'css/sticky_sidebar_headers.css',
+    },
+  ];
 
-  let outputPath = path.join(__dirname, 'dist', env.browser_target);
+  const outputPath = path.join(__dirname, 'dist', env.browser_target);
 
-  let overridenLocalePaths =
+  const overridenLocalePaths =
       localeOverrides.map(l => '**/_locales/' + l.pontoonLocale);
 
   let preprocessorLoader = {
@@ -129,10 +142,6 @@
                 __dirname, 'src/icons', env.canary ? 'canary' : 'regular'),
             to: path.join(outputPath, 'icons'),
           },
-        ]
-      }),
-      new CopyWebpackPlugin({
-        patterns: [
           {
             from: path.join(__dirname, 'src/static'),
             to: outputPath,
@@ -140,6 +149,7 @@
               ignore: ['**/OWNERS', '**.md', ...overridenLocalePaths],
             }
           },
+          ...getStylesCopyPatterns(styles),
         ]
       }),
       new HtmlWebpackPlugin({
@@ -244,3 +254,28 @@
     },
   };
 };
+
+const getCopyPluginsForOverridenLocales = outputPath => {
+  return localeOverrides.map(l => {
+    return new CopyWebpackPlugin({
+      patterns: [
+        {
+          from: path.join(__dirname, 'src/static/_locales/' + l.pontoonLocale),
+          to: path.join(outputPath, '_locales/' + l.webExtLocale),
+          globOptions: {
+            ignore: ['**/OWNERS', '**.md'],
+          }
+        },
+      ]
+    });
+  });
+};
+
+const getStylesCopyPatterns = styles => {
+  return styles.map(s => {
+    return {
+      from: path.join(__dirname, s.origin),
+      to: s.destination,
+    };
+  });
+}