Using webpack-merge for both module loaders and plugins

We have multiple webpack configuration files, and I need to restructure them to share common configuration

Current file structure

  • webpack.prod.js
  • webpack.dev.js

New file structure

  • webpack.common.js
  • webpack.prod.js
  • webpack.dev.js

The prod and dev files will use webpack-merge to merge their contents with the common file. However, there are a number of places that need different merge rules, and I have been unable to find anything clear about using different merge rules together.

Here is some sample configuration to highlight what I am trying to do

// webpack.common.js

const commonConfig = {

    module: {
        rules: [
            {
                test: /.css$/,
                use: ["css-loader"]
            },
        ]
    },
    plugins: [
            new webpack.EnvironmentPlugin({
                MY_ENV_1: "Common_value_1",
                MY_ENV_2: "Common_value_2",
                MY_ENV_3: "Common_value_3",
            }),
        ],
}

// webpack.dev.js

const devConfig = {

    module: {
        rules: [
            {
                test: /.css$/,
                use: ["style-loader"]
            },
        ]
    },
}

// webpack.prod.js

const prodConfig = {

    module: {
        rules: [
            {
                test: /.css$/,
                use: [MiniCssExtractPlugin.loader,]
            },
        ]
    },
    plugins: [
            new webpack.EnvironmentPlugin({
                MY_ENV_1: "Prod_value_1",
                MY_ENV_2: "Prod_value_2",
            }),
        ],

}

Here are my attempts at merging. As you can see, I have only got as far as doing each individually, as I am not happy with the individual outputs. But I would eventually like to only need a single merge, assuming that is possible.

const { mergeWithRules, mergeWithCustomize, CustomizeRule, unique } = require("webpack-merge");

const merge1 = mergeWithRules({
  module: {
    rules: {
      test: CustomizeRule.Match,
      use: CustomizeRule.Prepend,
    },
  },
})(commonConfig, prodConfig);


const merge2 = mergeWithCustomize({
  customizeArray: unique(
        "plugins",
        ["EnvironmentPlugin"],
        (plugin) => plugin.constructor && plugin.constructor.name,
      ),
  })(commonConfig, prodConfig);

This is the current output I produce.

// merge 1 output - I'm not clear what has happened to the test value
{
    "module": {
        "rules": [
            {
                "test": {},
                "use": [
                    "Resolved/Path/To/loader.js,
                    "css-loader"
                ]
            }
        ]
    },
    "plugins": [
        {
            "keys": [
                "MY_ENV_1",
                "MY_ENV_2",
                "MY_ENV_3"
            ],
            "defaultValues": {
                "MY_ENV_1": "Common_value_1",
                "MY_ENV_2": "Common_value_2",
                "MY_ENV_3": "Common_value_3"
            }
        },
        {
            "keys": [
                "MY_ENV_1",
                "MY_ENV_2"
            ],
            "defaultValues": {
                "MY_ENV_1": "Prod_value_1",
                "MY_ENV_2": "Prod_value_2"
            }
        }
    ]
}

// merge 2 output - only one set of ENV values is used
{
    "module": {
        "rules": [
            {
                "test": {},
                "use": [
                    "css-loader"
                ]
            },
            {
                "test": {},
                "use": [
                    "Resolved/Path/To/loader.js,
                ]
            }
        ]
    },
    "plugins": [
        {
            "keys": [
                "MY_ENV_1",
                "MY_ENV_2"
            ],
            "defaultValues": {
                "MY_ENV_1": "Prod_value_1",
                "MY_ENV_2": "Prod_value_2"
            } // Should also have "MY_ENV_3": "Common_value_3"
        }
    ]
}

How to use paylaod cms Jobs Queue

I am new to paylaod cms & trying to use Jobs Queue, just trying to send email every minute and testing on local machine

here is my payload.config.ts

export default buildConfig({
   jobs: {
    access: {
      run: ({ req }: { req: PayloadRequest }): boolean => {
        // Allow logged in users to execute this endpoint (default)
        if (req.user) return true

        // If there is no logged in user, then check
        // for the Vercel Cron secret to be present as an
        // Authorization header:
        const authHeader = req.headers.get('authorization')
        return authHeader === `Bearer ${process.env.CRON_SECRET}`
      },
    },
    tasks: [
      {
        slug: 'demoTask',
        inputSchema: [
          {
            name: 'time',
            type: 'text',
            required: true,
          },
        ],

        // These are the properties that the function should output
        outputSchema: [
          {
            name: 'text',
            type: 'text',
            required: true,
          },
        ],
        handler: async ({ input, req }) => {
          await req.payload.sendEmail({
            to: '[email protected]',
            subject: 'This is a demoQueue email',
            text: `This is a demoQueue email ${input.time}`,
          })
          return {
            output: {
              text: `${input} loged`,
            },
          }
        },
      },
    ],
    workflows: [
      {
        slug: 'demoWorkflow',
        handler: async ({ job, tasks }) => {
          await tasks.demoTask('1', {
            input: {
              time: `${new Date().toISOString()}`,
            },
          })
        },
        queue: 'demoQueue',
      },
    ],

    autoRun: [
      {
        cron: '* * * * *', // every minute
        limit: 1, // limit jobs to process each run
        queue: 'demoQueue', // name of the queue
      },
    ],
  },
  email: resendAdapter({
    defaultFromAddress: '[email protected]',
    defaultFromName: 'Project Name',
    apiKey: process.env.RESEND_API_KEY!,
  }),
})

but this is not working even I try with command

npx payload jobs:run --queue demoQueue --limit 1

error on the command

MongoNotConnectedError: Client must be connected before running operations

but I check with other operation MongoDB connection working fine
even I try to send email with collection hook “afterChange”, email working fine

can anyone help where I am making mistake

Thanks in advance

css gets transitioned at first mount

I have a svelte app that mounts some progress dots into a pretty plain html site.

simplified the ProgressDots.svelte has this:

hello
<div class="progress-dots">
  <div class="progress-dots__dot"></div>
</div>

<style>
    .progress-dots {
        display: flex;
        justify-content: center;
    }

    .progress-dots__dot {
        width: 10px;
        aspect-ratio: 1 / 1;
        background: #ccc;
        border-radius: 100%;
        transition: background 0.3s ease-in-out
    }
</style>

The problem I am facing is that when the component is first mounted I am getting a transition on the .progress-dots__dot element. It looks like it is going from transparent to #ccc.

I’ve added the hello at the root of the component so that I can verify that it isn’t an opacity effect or something like that on the component. It is just the .progress-dots__dot that is transitioning.

So some potential leads that I’ve found but haven’t been able to verify is that in my built js file it has included the css for the dots, so maybe that isn’t loaded before the element is added?

also when doing a performance recording I am getting this:

enter image description here

Threejs shadow not rendered properly [closed]

shadow not rendered as expected

Why shadows are not rendered properly and there are gradient like issues

const light = new DirectionalLight(tint, 2.5);
light.position.set(-20, 90, 4);
const helper = new CameraHelper(light.shadow.camera);
this.scene.add(helper);
light.castShadow = true;
const factor = 2;
light.shadow.mapSize.width = 512 * factor;
light.shadow.mapSize.height = 512 * factor;
const val = 1000;
light.shadow.camera.left = -val;
light.shadow.camera.right = val;
light.shadow.camera.top = val;
light.shadow.camera.bottom = -val;
light.shadow.camera.near = 0.5;
light.shadow.camera.far = 100;
this.scene.add(light);

Threejs shadow not rendered properly

shadow not rendered as expected

Why shadows are not rendered properly and there are gradient like issues

const light = new DirectionalLight(tint, 2.5);
light.position.set(-20, 90, 4);
const helper = new CameraHelper(light.shadow.camera);
this.scene.add(helper);
light.castShadow = true;
const factor = 2;
light.shadow.mapSize.width = 512 * factor;
light.shadow.mapSize.height = 512 * factor;
const val = 1000;
light.shadow.camera.left = -val;
light.shadow.camera.right = val;
light.shadow.camera.top = val;
light.shadow.camera.bottom = -val;
light.shadow.camera.near = 0.5;
light.shadow.camera.far = 100;
this.scene.add(light);

foundation slider with active thumbnail in the visible area

i’m using the orbit modul from foundation that works fine. I have reused the area of the bullets for the thumbnails of the large slider images. This also works so far, the active thumbnail is also marked as active.

Foundation has created an area here that expands downwards. I have arranged the thumbnails in a row using CSS.

My problem here is that after a few thumbnails the active one disappears from the visible area. I would like to have the active thumbnail in the visible area. Is there a solution from Foundation that I have not discovered? How would I have to add the JavaScirpt for this? Can anyone give me a tip here?

I would like to switch to another slider, because the Foundation Slider offers the possibility to display the images in the slider for the respective size of the browser viewport.

If you know of another slider that has a similar function, I would also be interested.

Many thanks for your help
m.orange

How to create a layout that only has all even or all odd row size, and changes by only 2?

I have been iterating with both Claude 3.7 Sonnet, and ChatGPT 4o, for days and days, trying to get this to be exactly how I want it, but it keeps making mistakes in the algorithm, and on an on in making the same mistakes in basically a circle.

How do I make a “layout” (array of integers), which represents a grid, which has the following constraints:

  1. The function is generateGridLayout(n, minColumns, maxColumns), where practically speaking it is usually called as gen(n, 3, 7), but could in theory be anything which would make a nice grid, say gen(n, 2, 256) as the max range.
  2. It should handle arbitrary number of elements (say up to Number.MAX_SAFE_INTEGER, which is 9007199254740991, but practically my “grid layouts” will only have mainly up to 1000 items).
  3. If the number of items n is odd, then each row should only have an odd number of values. If n is even, then each row can have either even or odd numbers (think 30, can be 10 rows of 3, or 3 rows of 10).
  4. The rows can only ever differ by 2 in size, always decreasing. It can’t ever differ by 3, 4, etc.. This means that 7 CANNOT be [5, 2] or [4, 4, 1], as those have jumps > 2. It can only be [7] or [3, 3, 1], if gen(7, 3, 7).
  5. (meta note, this is for a UI layout, so it is based on viewport/container size, so if we say “max is 7”, but there is only space for 5, it will set the max to 5, this fact isn’t really relevant for the solution though)
  6. If we say “max is 7”, but there is an even number of items, and the even number can’t satisfy “all even or all odd rows”, then try maxColumns - 1, and so on, down to minColumns.
  7. Important: it should minimize the number of small sized rows. So for 29, at 6 maxColumns, it should be [5, 5, 5, 5, 5, 3, 1], not [5, 5, 5, 5, 3, 3, 3]. That is, it maximizes the number of large rows, and minimizes the numbers of small rows. Likewise for 29, it should definitely not be [5, 5, 5, 5, 3, 3, 1, 1, 1].

Here are some examples to demonstrate the goal:

31
[5, 5, 5, 5, 5, 3, 3]
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1]

30
[5, 5, 5, 5, 5, 5]
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3]

29
[5, 5, 5, 5, 5, 3, 1]
[3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1]

28
[6, 6, 6, 6, 4]
[4, 4, 4, 4, 4, 4, 4]

27
[5, 5, 5, 5, 3, 3, 1]
[3, 3, 3, 3, 3, 3, 3, 3, 3]

26
[6, 6, 6, 4, 2, 2]
[4, 4, 4, 4, 4, 4, 4]

23
[5, 5, 5, 5, 3]
[3, 3, 3, 3, 3, 3, 3, 1, 1]

These show, if 5 or 6 is the max columns, what it would do, and what it should do if 4 or 3 is the max columns.

For example, 26 at 7 max columns should NOT be:

[6, 6, 6, 6, 2] # jumps more than 2
[4, 4, 4, 4, 4, 4, 2] # doesn't maximize maxColumns

It should ideally be:

[6, 6, 6, 4, 2, 2] # jumps max 2, maximizes large columns, minimizes small columns.

Here is my current solution:

log(29, 2, 7)
log(29, 2, 6)
log(29, 2, 5)
log(29, 2, 4)
log(44, 2, 3)

function distributeGridLayout(
  length,
  minColumns,
  maxColumns
) {
  function recur(
    dp,
    length,
    width,
  ) {
    if (length == 0) {
      return []
    }

    if (length < width - 2 || width <= 0) {
      return
    }

    if (dp[width].has(length)) {
      return
    }

    dp[width].add(length)

    for (let i = 0; i < 2; i++) {
      let result = recur(dp, length - width, width)
      if (result) {
        return [width, ...result]
      }
      width -= 2
    }

    return
  }

  if (length <= maxColumns) {
    return [length]
  }

  if (maxColumns >= 3 && length === 7) {
    return [3, 3, 1]
  }

  if (maxColumns >= minColumns && length % maxColumns === 0) {
    const result = []
    while (length) {
      result.push(maxColumns)
      length -= maxColumns
    }
    return result
  }

  if (maxColumns > 4) {
    if (maxColumns > minColumns && length % (maxColumns - 1) === 0) {
      const result = []
      maxColumns--
      while (length) {
        result.push(maxColumns)
        length -= maxColumns
      }
      return result
    }
  }

  const dec = 2 - (length % 2)

  maxColumns -= maxColumns % dec

  const dp = Array.from(
    { length: maxColumns + 1 },
    () => new Set(),
  )

  for (let width = maxColumns; width > 0; width -= dec) {
    const result = recur(dp, length - width, width)
    if (result) {
      if (width <= minColumns) {
        return
      }
      return [width, ...result]
    }
  }

  return
}

function log(n, min, max) {
  const grid = distributeGridLayout(n, min, max)
  console.log(`gen(${n}, ${min}, ${max})`, grid)
}

That is working for most, like this Tibetan layout (29 chars):

But it is not working for this Thai layout (44 chars, in 2-3 columns), here is the end of it (in my UI, if the algorithm returns undefined, it falls back to a basic grid layout):

What do I need to change exactly so this always fits my rules? The 44 layout of 3 max 2 min should be basically a 2 column layout…

ChartJS make container fill whole CSS grid item

I’m putting a chart (made using Chart.js) inside a CSS grid, and I want the chart to responsively fill the full width of its grid cell. However, even after turning on responsive and turning off maintainAspectRatio for the chart, the chart does not redraw to fill the container if the viewport is widened enough.

To reproduce:

<main>
    <div id="chart-container">
        <canvas id="chart"></canvas>
    </div>
    <div id="other">Some other data here</div>
</main>

<style>
    main {
        width: 100%;
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        grid-template-areas:
            'chart chart more';
    }
    #chart-container {
        grid-area: chart;
    }
    #other {
        grid-area: more;
    }
</style>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

<script>
    const chartElement = document.getElementById('chart');
    new Chart(chartElement, {
        type: 'line',
        responsive: true,
        maintainAspectRatio: false,
        data: {
            labels: ['January', 'February', 'March', 'April', 'May', 'June'],
            datasets: [{
                label: 'Sample Data',
                data: [17, 15, 8, 2, 12, 19]
            }]
        }
    });
</script>

Here are screenshots with grid lines turned on in the developer tools to illustrate the issue.

Normal viewport width:
The chart when the viewport is at a normal width, as expected.

Wider viewport:
The chart when the viewport is widened, the chart does not resize.

If I add width: 100% to the container, there is no difference in the resizing. If I add width: 100% to the canvas element, the chart becomes distorted (like when you resize an image horizontally but not vertically). I also added the following in an attempt to force the resize event to fire on the chart upon window resize, with no difference:

window.addEventListener('beforeprint', () => {
    chartElement.resize();
})

I’ve been scouring the Chart.js documentation for other possible solutions, but haven’t found any. Is there a way to make the chart redraw to take up the full grid cell width when the viewport is resized? Thanks in advance!

My website keeps crashing when I try to upload an image [closed]

I am making a resume builder in Next.js and I am using React-Hook-Form with Zod and Shadcn.

"use client"

import { Button } from "@/components/ui/button";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { personalInfoSchema } from "@/lib/formValidations";
import { zodResolver } from "@hookform/resolvers/zod";
import React, { useEffect, useRef } from "react";
import { useForm } from "react-hook-form";

const PersonalInforForm = ({ resumeData = {}, setResumeData = "" }) => {
  const form = useForm({
    resolver: zodResolver(personalInfoSchema),
    defaultValues: {
      firstName: resumeData.firstName || "",
      lastName: resumeData.lastName || "",
      jobTitle: resumeData.jobTitle || "",
      city: resumeData.city || "",
      country: resumeData.country || "",
      phone: resumeData.phone || "",
      email: resumeData.email || "",
    },
  });

  useEffect(() => {
    const { unsubscribe } = form.watch(async () => {
      const isValid = await form.trigger();

      if (!isValid) return;

      //update resume
    });

    return unsubscribe;
  }, [form]);

  const photoInputRef = useRef(null);

  return (
    <div className="mx-autp max-w-xl space-y-6">
      <div className="space-y-1.5 text-center">
        <h2 className="text-2xl font-semibold">Personal info</h2>
        <p className="text-sm text-muted-foreground">Tell us about yourself.</p>
      </div>
      <Form {...form}>
        <form className="space-y-3">
          <FormField
            control={form.control}
            name="photo"
            render={({ field: { value, ...fieldValues } }) => (
              <FormItem>
                <FormLabel>Your photo</FormLabel>
                <div className="flex items-center gap-2">
                  <FormControl>
                    <Input
                      {...fieldValues}
                      type="file"
                      accept="image/*"
                      onChange={(e) => {
                        const file = e.target.files[0];
                        fieldValues.onChange(file);
                      }}
                      ref={photoInputRef}
                    />
                  </FormControl>
                  <Button
                    variant="secondary"
                    type="button"
                    onClick={() => {
                      fieldValues.onChange(null);
                      if (photoInputRef.current) {
                        photoInputRef.current.value = "";
                      }
                    }}
                  >
                    Remove
                  </Button>
                </div>
                <FormMessage />
              </FormItem>
            )}
          />
        </form>
      </Form>
    </div>
  );
};

export default PersonalInforForm;

I have even tried some copying some people over at Youtube but it didn’t work.

When I try to upload even much smaller images than the limit (literally a few 100 kbs) the page gets stuck. I don’t know what to do. Is this due to any hardware issues?

How do I extract forum post content from AoPS when it’s visible in the browser but missing from driver.page_source?

I am not a web developer but an olympiad instructor with no coding experience who is using chatgpt to scrape math problems for personal use. I have been stuck at the following problem for 10+ hours. The following content is the summary produced by AI and the broad bits are right but I dont get the technical bits.

Details: I’m trying to scrape forum post content from Art of Problem Solving (AoPS) — specifically from threads like this one:

https://artofproblemsolving.com/community/c6h86541p504698

In the browser, the full post is visible — it includes a clean math problem and a solution.

But when I try to extract content using Python + Selenium, the post is completely missing from driver.page_source.

What I’ve tried:
• Selenium waits:

WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CLASS_NAME, "post-text"))
)
```Also tried cmty-post-content, post_message, and others.

• Scrolling:

driver.execute_script(“window.scrollTo(0, document.body.scrollHeight)”)

• Looking for post by ID:
The URL includes p504698, so I tried:

soup.find(“div”, id=”post_504698″)

Nothing found.

• Content-based div scraping:
Scanned all <div>s looking for math-like keywords (“Let”, “prove”, “=”). This sometimes works — but not consistently.

•JS evaluation:

driver.execute_script(“return document.body.innerText”)

Still misses the post.


What’s likely happening?
It seems AoPS injects the post after page load, possibly using deferred JavaScript or Shadow DOM. The post isn’t part of the initial DOM snapshot, and doesn’t show up in driver.page_source or standard find_element() lookups.


Relevant threads I’ve consulted:
- [Content not in page source (57956324)](https://stackoverflow.com/questions/57956324/not-able-to-scrape-dynamic-content-using-selenium-or-beautifulsoup)
- [Use JavaScript extraction (63314833)](https://stackoverflow.com/questions/63314833/how-to-scrape-data-from-a-dynamic-website-with-selenium)
- [General dynamic scraping (36779288)](https://stackoverflow.com/questions/36779288/scraping-dynamic-content-through-selenium)
- [Get dynamic content with JS (15456872)](https://stackoverflow.com/questions/15456872/getting-dynamic-content-from-a-website-through-javascript)

None of them seem to solve this edge case.

What I’m looking for:
• How can I reliably extract just the actual forum post text, ideally as div.text or similar?
• Should I be targeting a particular JS variable, event trigger, or DOM mutation?
• Do I need to use MutationObserver or intercept XHR calls?

Would love help from anyone who’s scraped AoPS, Discourse, or similar JS-heavy forum platforms.

Optimizing weather animations (snow/rain/stars) for mobile – alternatives to 100+ CSS animated elements? [closed]

I’m building a weather-themed portfolio with interactive animations that must maintain performance on mobile devices (≥ iPhone 8/Android 9). While I’ve made optimizations, I’m hitting performance limits with the current CSS-based approach.

  1. Frame drops (especially on older devices like iPhone 8)

  2. High battery consumption

  3. Jitter during scrolling

<!-- Simplified snowflake example -->
<div class="snowflake"></div>
<style>
  .snowflake {
    position: fixed;
    width: 8px;
    height: 8px;
    background: white;
    border-radius: 50%;
    animation: fall 8s linear infinite;
    will-change: transform;
  }
  @keyframes fall {
    to { transform: translateY(100vh) rotate(360deg); }
  }
</style>

Performance (Moto G5/Chrome):

  • 50 snowflakes: ~40fps, +150MB GPU memory

  • 60 raindrops + ripples: CPU ~25% sustained

  • 200 stars: Significant scroll jitter

What I’ve Tried:

  1. Reduced elements (100 → 50 snowflakes)

  2. Optimized with will-change: transform and translateZ(0)

  3. Implemented requestAnimationFrame for JS control

  4. Added prefers-reduced-motion support

Core Questions:

  1. Element Limits: Is there a recommended maximum number of concurrently animated elements for mobile?

  2. Technology Choice: At what point should I switch from CSS to:

    • Canvas (requestAnimationFrame + object pooling)

    • SVG (SMIL animations)

    • WebGL (PixiJS/Three.js)

  3. Scroll Performance: Best practices to prevent jitter when many elements are animating during scroll?

Constraints:

  • Must maintain visual quality (snowflakes need individual movement)

  • Should work on mid-range mobile devices

  • Prefers-reduced-motion support required

Unselecting and other weird behaviors like tapping outside deselect sometimes when the app is tested on a real phone, but works in pc mobile size

This is very weird, when you select the same hour that you selected it should deselect it but it doesn’t work when tested on a real phone. When i test it in my pc using mobile size 290 width pixels works fine but then in a real phone it doesnt, to make it even more weird is that the problem happens in angular and remix but not in next.js. In next.js the feature works just fine. The logic is not the issue as I’ve already tested that in multiple ways and it works fine if the feature is next.js but the problem will arise in angular and remix.

Angular.

HTML:

<!--Third form--> 
<div class="form_outer_div">
    <div class="icon__wrapper_form">
        <p class="what_is_this_section_about">
            Operating Times
        </p>
        <button *ngIf="!thirdForm" (click)="openCloseThirdForm()" class="icon__styling__form">
            <lucide-angular [img]="ChevronDown" class="open_close_forms_icons"/>
        </button>

        <button *ngIf="thirdForm" (click)="openCloseThirdForm()" class="icon__styling__form">
            <lucide-angular [img]="ChevronUp" class="open_close_forms_icons"/>
        </button>
    </div>

    <div *ngIf="thirdForm" class="centering_grid_div_content_base_class_no_border">
        <div>
            <p class="gray_p">Choose Operating Time</p>
            <input class="input_fields" readonly/>
            <div class="centering_grid_div_content_base_class_no_border">
                <div class="flex_centering_no_border">

                    <div class="flex_centering_no_border">
                        <p class="small_gray_p">opening time</p>

                        <button *ngIf="!openingTimeSection" (click)="handleOpeningTimeSection()">
                            <i-lucide [img]="ChevronDown" />
                        </button>

                        <button *ngIf="openingTimeSection" (click)="handleOpeningTimeSection()">
                            <i-lucide [img]="X" />
                        </button>
                    </div>

                    <div class="flex_centering_no_border">
                        <p class="small_gray_p">closing time</p>

                        <button *ngIf="!closingTimeSection" (click)="handleClosingTimeSection()">
                            <i-lucide [img]="ChevronDown"/>
                        </button>

                        <button *ngIf="closingTimeSection" (click)="handleClosingTimeSection()">
                            <i-lucide [img]="X"/>
                        </button>
                    </div>
                </div>

                <div *ngIf="openingTimeSection" class="blink_on_render div_flex_centering_with_border">
                    <!--Hour--> 
                    <div class="container_holding_certain_type_of_time">
                        <div class="small_text_red_color_within_div">
                            hh
                        </div>
                        <div class="time_div_content">
                            <div *ngFor="let hour of hours" class="loop_content_div" (click)="handleChooseOpeningHour(hour)"
                                [ngClass]="{'set_background_bg_sky_600': openHourSelected === hour}"
                            >
                                {{hour}}
                            </div>
                        </div>
                    </div>
                </div>

            </div>
        </div>
    </div>
</div>

Component:

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LucideAngularModule, ChevronDown, ChevronUp, X } from 'lucide-angular';

@Component({
  selector: 'app-create-operating-times',
  imports: [LucideAngularModule, CommonModule],
  templateUrl: './create-operating-times.component.html',
  styleUrl: './create-operating-times.component.scss'
})
export class CreateOperatingTimesComponent {

  //Icons
  readonly ChevronDown =  ChevronDown;
  readonly ChevronUp = ChevronUp;
  readonly X = X;

  //Loop data for time
  readonly hours = Array.from({length: 24}, (_, h) => h.toString().padStart(2, '0'));
  readonly minutes = Array.from({length: 60}, (_, m) => m.toString().padStart(2, '0'));

  //third form related
  thirdForm: boolean = false;
  openingTimeSection: boolean = false;
  closingTimeSection: boolean = false;
  openHourSelected: string = "";


  openCloseThirdForm(){
    if(!this.thirdForm){
      this.thirdForm = true;
      this.openingTimeSection = true;
      this.closingTimeSection = false;
    }else{
      this.thirdForm = false;
      this.openingTimeSection = false;
      this.closingTimeSection = false;
    }
  }

  handleOpeningTimeSection(){
    if(!this.openingTimeSection){
      this.openingTimeSection = true;
      this.closingTimeSection = false;
    }else{
      this.openingTimeSection = false;
    }
  }

  handleChooseOpeningHour(hour: string){
    if(this.openHourSelected === hour){
      this.openHourSelected = ""
    }else{
      this.openHourSelected = hour;
    }
  }

  handleClosingTimeSection(){
    if(!this.closingTimeSection){
      this.openingTimeSection = false;
      this.closingTimeSection = true;
    }else{
      this.closingTimeSection = false;
    }
  }
}

SCSS:

html {
    touch-action: manipulation;
    width: 100%;
}

.container{
    max-width: 100%;
    margin-left: auto;
    margin-right: auto;
    padding-left: 0.5rem;
    padding-right: 0.5rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;

}

.form_outer_div{
    border-width: 1px; /* Tailwind's 'border' */
    border-radius: 0.375rem; /* Tailwind's 'rounded-md' */
    border-color: #1e3a8a; /* Tailwind's 'border-blue-900' */
    padding: 0.5rem; /* Tailwind's 'p-2' */
    margin: 0; /* Tailwind's 'mb-2' */
    display: grid; /* Tailwind's 'grid' */
    width: 100%; /* Tailwind's 'w-full' */
    border: 2px solid #1e3a8a;;
}

.flex_centering_no_border{
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
}

.centering_grid_div_content_base_class{
    display: grid;
    border-radius: 0.375rem;
    border: 1px solid #1e40af;
    text-align: center;
    justify-items: center;
    padding: 0.5rem;
}

.centering_grid_div_content_base_class_no_border{
    display: grid;
    border-radius: 0.375rem;
    text-align: center;
    justify-items: center;
    padding: 0.5rem;
}

.div_flex_centering_with_border{
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    border: 2px solid #1e40af; /* border-blue-900 */
    border-radius: 0.375rem; /* rounded-md */
    padding-top: 0.25rem; /* pt-1 */
    padding-bottom: 0.25rem; /* pb-1 */
}

.input_fields, .input_fields::placeholder{
    border-width: 1px;
    border-style: solid;
    border-color: #1e3a8a; /* Tailwind's border-blue-900 */
    border-radius: 0.375rem; /* rounded-md */
    text-align: center;
    margin: 0; /* mb-2 */
    caret-color: transparent;
    height: 2rem;
}

.small_text_red_color_within_div{
    display: flex;
    font-weight: bold;
    justify-content: center;
    color: #ef4444;
    font-size: 16px;
}

.small_gray_p{
    color: #6b7280; /* Tailwind's gray-500 */
    font-size: 1rem; /* Tailwind's text-xs */
    font-weight: bold;
}

.gray_p{
    font-size: 1.20rem; /* Tailwind's 'text-base' */
    color: #6b7280;  /* Tailwind's 'text-gray-500' */
    font-weight: bold;
}

.icon__wrapper_form{
    display: flex;
    justify-content: space-between;
}

.icon__styling__form{
    margin-bottom: 2px;
    padding-top: 0px;
}

::ng-deep .open_close_forms_icons svg {
    width: 32px !important;
    height: 32px !important;
    stroke-width: 3;
    stroke: #1e3a8a;
}

.div_what_is_section_about_and_icon{
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
}

.p_operating_times{
    color: #6b7280;  /* Equivalent to text-gray-500 in Tailwind */
    font-size: 0.75rem;  /* Equivalent to text-xs in Tailwind */
}

.container_holding_certain_type_of_time{
    @extend .centering_grid_div_content_base_class;
    height: 15rem;
    border-width: 1px;
    border-style: solid;
    border-color: #e5e7eb; /* Default border color in Tailwind */
}

.what_is_this_section_about{
    color: #3B82F6; /*blue-500*/
    margin-bottom: 2px;
    font-weight: bold;
    font-size: 1.35rem; 
}

.time_labeling{
    display: flex;
    color: #f87171; /* Tailwind's red-500 color */
    font-weight: bold;
    font-size: 0.875rem; /* 14px */
    justify-content: center
}

.loop_content_div{
    border-top: 1px solid #3b82f6;
    padding: 0.25rem; /* 4px */
    border-bottom: 1px solid #3b82f6; /* Tailwind's blue-500 color */
    cursor: pointer;
    width: 48px;
}

.loop_content_div:hover{
    @extend .hover_effect_sky_600;
}

.time_div_content{
    -webkit-tap-highlight-color: transparent; /* Hide tap highlight */
    touch-action: manipulation; /* Reduce delay on Android */
    display: grid;
    border-radius: 0.375rem;
    border-color: #1e3a8a; /* Tailwind's blue-900 color */
    padding: 0.25rem; /* 4px */
    height: 100%;
    overflow-y: auto;
    width: 100%;
     /* Mobile interaction helpers */
    -webkit-overflow-scrolling: touch;
    touch-action: manipulation;
    pointer-events: auto;
}

/* xs */
@media (min-width: 475px) {
    .container {
        max-width: 475px;
    }
}

/* sm */
@media (min-width: 640px) {
    .container {
        max-width: 640px;
    }
}

/* md */
@media (min-width: 768px) {
    .container {
        max-width: 768px;
    }
}

/* lg */
@media (min-width: 1024px) {
    .container {
        max-width: 1024px;
    }
}

/* lx */
@media (min-width: 1280px) {
    .container {
        max-width: 1280px;
    }
}

/* 2xl*/
@media (min-width: 1536px) {
    .container {
        max-width: 1536px;
    }
}

//Conditional styling
.set_background_bg_sky_600{
    background-color: #0284c7;
}

//Hover effects
.hover_effect_sky_600{
    background-color: #0284c7;
}

/* Animations and transition */

@keyframes blinkFade {
    0% {
        opacity: 0;
    }
    10%{
        opacity: 1;
    }
}

.blink_on_render{
    animation: blinkFade 0.2s ease-in-out;
}

As i said this is very weird because creating the same exact feature in next.js works just fine in a real phone but the problem i described before happens in angular and remix. When i tested the feature in the browser using mobile size it worked but not in a real phone. Thanks for helping