#from jsx to .astro

15 messages · Page 1 of 1 (latest)

burnt linden
#

can you pass this to astro?
import { useEffect, useState } from "react";

const { data } = Astro.props;

const StreamIsland = () => {
const [randomStream, setRandomStream] = useState(null);
const [currentDomain, setCurrentDomain] = useState("");

useEffect(() => {
if (typeof window !== "undefined") {
setCurrentDomain(window.location.hostname);

  const fetchStreams = async () => {
    try {
      if (data.success) {
        const livePlayers = data.result.flatMap((team) => team.teamPlayers.filter((player) => player.player.isLive));

        if (livePlayers.length > 0) {
          const randomPlayer = livePlayers[Math.floor(Math.random() * livePlayers.length)];
          setRandomStream(randomPlayer.player.twitch);
        }
      }
    } catch (error) {
      console.error("Error fetching streams:", error);
    }
  };

  fetchStreams();
}

}, []);

return (
<div className="mt-10 md:mt-20 rounded-xl py-4">
<div
id="container"
className="flex flex-col md:flex-row justify-center items-center gap-6 rounded-2xl p-4 lg:p-0"
style={{ background: "rgba(65, 63, 65, 0.152)" }}
>
{/* YouTube Video */}
<div className="relative flex justify-center items-center w-full md:w-[600px] lg:w-[640px] h-[250px] md:h-[340px] lg:h-[400px] rounded-lg">
<div className="relative z-1 w-[310px] md:w-[580px] lg:w-[590px] h-[230px] md:h-[320px] lg:h-[340px] rounded-md overflow-hidden border-[2px] border-solid border-[#9B7934]">
<iframe
name="Vídeo de Presentación"
src="https://www.youtube.com/embed/CqmFOV4QH88?si=2PHstK8vdvIJS0Nb"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerPolicy="strict-origin-when-cross-origin"
allowFullScreen
className="w-full h-full rounded-md"
></iframe>
</div>
</div>

    {/* Twitch Stream */}
    <div className="relative flex justify-center items-center w-full md:w-[600px] lg:w-[640px] h-[240px] md:h-[340px] lg:h-[400px] rounded-lg">
      <div className="relative z-1 w-[310px] md:w-[580px] lg:w-[590px] h-[230px] md:h-[320px] lg:h-[340px] rounded-md overflow-hidden border-[2px] border-solid border-[#9B7934]">
        {randomStream ? (
          <iframe
            name="Retransmisión en Twitch"
            id="twitch-iframe"
            src={`https://player.twitch.tv/?channel=${randomStream}&parent=${currentDomain}&autoplay=false`}
            frameBorder="0"
            allowFullScreen
            scrolling="no"
            className="w-full h-full rounded-md"
          ></iframe>
        ) : (
          <p className="text-center">Cargando stream en vivo...</p>
        )}
      </div>
    </div>
  </div>
</div>

);
};

export default StreamIsland;

5 equipos, un objetivo: llegar a Challenger el primero. ¡Os presentamos First to Challenger!

Xokas, Skain, Elmillor, Werlyb y Alvarostorm serán los capitanes de los equipos en este reto de League of Legends. La batalla comienza en enero, ¡no te pierdas las partidas en los canales de los creadores participantes!

https://first2challenger.es/

--...

▶ Play video
modest swanBOT
#

Hi @burnt linden. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

To convert this React component to an Astro component, you'll need to make several changes. Here's how you can transform the JSX code into an .astro file:

---
// StreamIsland.astro
const { data } = Astro.props;

// Move the data processing logic to the frontmatter
let randomStream = null;
let currentDomain = '';

if (data.success) {
  const livePlayers = data.result.flatMap((team) => team.teamPlayers.filter((player) => player.player.isLive));
  if (livePlayers.length > 0) {
    const randomPlayer = livePlayers[Math.floor(Math.random() * livePlayers.length)];
    randomStream = randomPlayer.player.twitch;
  }
}

// You can't use `window` in the frontmatter, so we'll set it in the client-side script
---

<div class="mt-10 md:mt-20 rounded-xl py-4">
  <div
    id="container"
    class="flex flex-col md:flex-row justify-center items-center gap-6 rounded-2xl p-4 lg:p-0"
    style="background: rgba(65, 63, 65, 0.152)"
  >
    <!-- YouTube Video -->
    <div class="relative flex justify-center items-center w-full md:w-[600px] lg:w-[640px] h-[250px] md:h-[340px] lg:h-[400px] rounded-lg">
      <div class="relative z-1 w-[310px] md:w-[580px] lg:w-[590px] h-[230px] md:h-[320px] lg:h-[340px] rounded-md overflow-hidden border-[2px] border-solid border-[#9B7934]">
        <iframe
          name="Vídeo de Presentación"
          src="<https://www.youtube.com/embed/CqmFOV4QH88?si=2PHstK8vdvIJS0Nb">
          frameborder="0"
          allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
          referrerpolicy="strict-origin-when-cross-origin"
          allowfullscreen
          class="w-full h-full rounded-md"
        ></iframe>
      </div>
    </div>
#

<!-- Twitch Stream -->
<div class="relative flex justify-center items-center w-full md:w-[600px] lg:w-[640px] h-[240px] md:h-[340px] lg:h-[400px] rounded-lg">
<div class="relative z-1 w-[310px] md:w-[580px] lg:w-[590px] h-[230px] md:h-[320px] lg:h-[340px] rounded-md overflow-hidden border-[2px] border-solid border-[#9B7934]">
{randomStream ? (
<iframe
name="Retransmisión en Twitch"
id="twitch-iframe"
src={<https://player.twitch.tv/?channel=${randomStream}&parent=${currentDomain}&autoplay=false}>
frameborder="0"
allowfullscreen
scrolling="no"
class="w-full h-full rounded-md"
></iframe>
) : (
<p class="text-center">Cargando stream en vivo...</p>
)}
</div>
</div>
</div>
</div>

<script>
// Set the current domain on the client side
document.addEventListener('DOMContentLoaded', () => {
const currentDomain = window.location.hostname;
const twitchIframe = document.getElementById('twitch-iframe');
if (twitchIframe) {
const src = twitchIframe.getAttribute('src');
if (src) {
twitchIframe.setAttribute('src', src.replace('&parent=', &parent=${currentDomain}));
}
}
});
</script>


Here are the key changes made to convert the React component to an Astro component:
#
  1. The component logic is moved to the frontmatter section (between the --- delimiters) at the top of the file.
  2. React hooks (useState, useEffect) are removed as they are not used in Astro components.
  3. The data processing is done in the frontmatter, and the results are used directly in the HTML template.
  4. The className attribute is changed to class in the HTML.
  5. The currentDomain is set using a client-side script, as we can't access window in the frontmatter.
  6. The conditional rendering for the Twitch stream is kept using Astro's JSX-like syntax.

This conversion follows the guidelines for converting JSX files to .astro files and using framework components in Astro.

Remember that Astro components are static by default. If you need interactivity, you might need to use a client directive or consider keeping this as a React component and using it within an Astro page.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@burnt linden Kapa.ai is still learning and improving, please let me know how I did by reacting below.

burnt linden
#

The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.ts(2363)
var parent: Window
Refers to either the parent WindowProxy, or itself.

It can rarely be null e.g. for contentWindow of an iframe that is already removed from the parent.

MDN Reference

twitchIframe.setAttribute('src', src.replace('&parent=', &parent=${currentDomain}));

@modest swan

modest swanBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

The error you're encountering is related to TypeScript's type checking. It seems that the currentDomain variable is not being recognized as a string in the template literal. To resolve this issue and ensure type safety, we need to make a few adjustments to the code. Here's how you can fix it:

---
// Rest of your frontmatter code...
---

<!-- Rest of your HTML... -->

<script>
  // Set the current domain on the client side
  document.addEventListener('DOMContentLoaded', () => {
    const currentDomain = window.location.hostname;
    const twitchIframe = document.getElementById('twitch-iframe') as HTMLIFrameElement | null;
    if (twitchIframe) {
      const src = twitchIframe.getAttribute('src');
      if (src) {
        twitchIframe.setAttribute('src', src.replace('&parent=', `&parent=${currentDomain}`));
      }
    }
  });
</script>

Here are the key changes and explanations:

  1. We've added a type assertion for twitchIframe to explicitly tell TypeScript that it's an HTMLIFrameElement or null. This helps TypeScript understand what methods and properties are available on this element.

  2. The template literal syntax (`&parent=${currentDomain}`) is correct. The error you were seeing was likely due to TypeScript not recognizing currentDomain as a string. By declaring it with const, TypeScript should infer its type correctly.

  3. We're using optional chaining and null checks to ensure we only attempt to modify the src attribute if the iframe element and its current src attribute exist.

These changes should resolve the TypeScript error you were encountering. The code now properly sets the parent domain for the Twitch iframe on the client side, which is necessary because we can't access window in the Astro component's frontmatter.

#

If you're still encountering issues, you might need to check your TypeScript configuration. Make sure you have the correct tsconfig.json settings for your Astro project. You can refer to the Astro documentation on TypeScript for more information on configuring TypeScript in Astro projects.

Astro TypeScript Guide

Remember, this script runs on the client side, so it has access to the window object and can safely use window.location.hostname.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@burnt linden Kapa.ai is still learning and improving, please let me know how I did by reacting below.

burnt linden
#

how do I make this an island

<StreamIsland data={fetchedData} />

@modest swan

modest swanBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

To make the StreamIsland component an Astro island, you need to use a client directive. This will allow the component to be interactive on the client side. Here's how you can do it:

  1. First, make sure you have the appropriate UI framework integration installed. Since your original component was in React, I'll assume you want to use React. If you haven't already, install the React integration for Astro:
npx astro add react
  1. Keep your StreamIsland component as a React component (in a .jsx or .tsx file).

  2. In your Astro file where you want to use the StreamIsland component, import it and use a client directive. Here's an example:

---
import StreamIsland from '../components/StreamIsland.jsx';
const fetchedData = // ... your data fetching logic here
---

<StreamIsland client:load data={fetchedData} />

The client:load directive tells Astro to render this component on the client side as soon as the page loads. This makes it an "island" of interactivity in your otherwise static Astro page.

You can choose different client directives based on when you want the component to hydrate:

  • client:load: Loads and hydrates the component immediately on page load.
  • client:idle: Loads and hydrates the component once the page is done with its initial load and the requestIdleCallback event has fired.
  • client:visible: Loads and hydrates the component once it has entered the user's viewport.
  • client:media={query}: Loads and hydrates the component once a certain CSS media query is met.
  • client:only={framework}: Skips server-side rendering and only runs on the client.

Choose the directive that best fits your needs for when you want the StreamIsland component to become interactive.

#

For more information on using UI framework components in Astro and the available client directives, you can refer to the Astro documentation on framework components.

By using this approach, you're creating an Astro island - an interactive piece of UI within your static Astro site.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: