Merge pull request #2736 from RomanHotsiy/contentful-integration-plugin

chore: example plugin
This commit is contained in:
Aria Keshmiri
2024-08-26 07:29:06 -07:00
committed by GitHub
6 changed files with 662 additions and 937 deletions

View File

@@ -1,25 +1,28 @@
import { indexPages } from './plugins/index-pages.js';
import { codeSamples } from './plugins/code-samples.js';
import { blogPosts } from './plugins/blog-posts.js';
import { eventsContentful } from './plugins/events-contentful.js';
export default function customPlugin() {
const indexPagesInst = indexPages();
const codeSamplesInst = codeSamples();
const blogPostsInst = blogPosts();
const eventsContentfulInst = eventsContentful();
/** @type {import("@redocly/realm/dist/server/plugins/types").PluginInstance } */
/** @type {import("@redocly/realm/dist/server/plugins/types").LifecyclePluginInstance } */
const pluginInstance = {
processContent: async (content, actions) => {
await indexPagesInst.processContent?.(content, actions);
await codeSamplesInst.processContent?.(content, actions);
await blogPostsInst.processContent?.(content, actions);
id: 'xrpl',
processContent: async (actions, context) => {
await indexPagesInst.processContent?.(actions, context);
await codeSamplesInst.processContent?.(actions, context);
await blogPostsInst.processContent?.(actions, context);
await eventsContentfulInst.processContent?.(actions, context);
},
afterRoutesCreated: async (content, actions) => {
await indexPagesInst.afterRoutesCreated?.(content, actions);
await codeSamplesInst.afterRoutesCreated?.(content, actions);
await blogPostsInst.afterRoutesCreated?.(content, actions);
afterRoutesCreated: async (actions, context) => {
await indexPagesInst.afterRoutesCreated?.(actions, context);
await codeSamplesInst.afterRoutesCreated?.(actions, context);
await blogPostsInst.afterRoutesCreated?.(actions, context);
await eventsContentfulInst.afterRoutesCreated?.(actions, context);
},
};

View File

@@ -0,0 +1,21 @@
// @ts-check
import path from 'node:path';
const EVENTS_SERVER_PROPS_ID = 'contentful-events';
export function eventsContentful() {
/** @type {import("@redocly/realm/dist/server/plugins/types").LifecyclePluginInstance } */
const instance = {
id: 'events-contentful',
processContent: async (actions, { fs }) => {
actions.registerServerPropsGetter(EVENTS_SERVER_PROPS_ID, path.join(fs.cwd, 'community/events.server.ts'));
},
afterRoutesCreated: async (actions, context) => {
const route = actions.getRouteByFsPath('community/events.page.tsx');
if (route) {
route.serverPropsGetterIds = [...(route.serverPropsGetterIds || []), EVENTS_SERVER_PROPS_ID];
console.log('worked!!!');
}
},
};
return instance;
}

View File

@@ -1,20 +1,6 @@
"use strict";
import {
ApolloClient,
InMemoryCache,
ApolloProvider,
useQuery,
gql,
} from "@apollo/client";
import { useState, useMemo } from "react";
import { useThemeHooks } from "@redocly/theme/core/hooks";
const client = new ApolloClient({
uri: `https://graphql.contentful.com/content/v1/spaces/${process.env.PUBLIC_CONTENTFUL_SPACE_ID}`,
cache: new InMemoryCache(),
headers: {
Authorization: `Bearer ${process.env.PUBLIC_CONTENTFUL_ACCESS_TOKEN}`,
},
});
const moment = require("moment");
const amaImage = require("../static/img/events/AMAs.png");
const hackathon = require("../static/img/events/Hackathons.png");
@@ -37,28 +23,6 @@ const imageLookup = {
"info-session": require("../static/img/events/InfoSessions.png"),
};
const GET_EVENTS = gql`
query GetEvents {
eventsCollection {
items {
_id
name
description
category
link
location
startDate
endDate
community
image {
url
}
}
}
}
`;
export const frontmatter = {
seo: {
title: "Events",
@@ -877,11 +841,11 @@ const events = [
},
];
function Events() {
const { loading, error, data } = useQuery(GET_EVENTS);
export default function Events({pageProps}) {
const {data, errors} = pageProps.contentfulEvents;
const { useTranslate } = useThemeHooks();
const { translate } = useTranslate();
const { past, upcoming } = useMemo(() => categorizeDates(data?.eventsCollection?.items || []), [data,loading]);
const { past, upcoming } = useMemo(() => categorizeDates(data?.eventsCollection?.items || []), [data]);
const [upcomingFilters, setUpcomingFilters] = useState({
conference: true,
meetup: true,
@@ -930,355 +894,349 @@ function Events() {
}));
};
if (errors) {
return <div style={{color: 'red', padding: '20px'}}>{errors[0]?.message}</div>
}
return (
<ApolloProvider client={client}>
<div className="landing page-events">
<div>
<div className="position-relative d-none-sm">
<img
alt="orange waves"
src={require("../static/img/backgrounds/events-orange.svg")}
id="events-orange"
/>
</div>
<section className="text-center py-26">
<div className="mx-auto text-center col-lg-5">
<div className="d-flex flex-column-reverse">
<h1 className="mb-0">
{translate("Find the XRPL Community Around the World")}
</h1>
<h6 className="mb-3 eyebrow">{translate("Events")}</h6>
</div>
</div>
</section>
<section className="container-new py-26">
<div className="event-hero card-grid card-grid-2xN">
<div className="pr-2 col">
<img
alt="xrp ledger apex hero"
src={require("../static/img/events/event-hero3@2x.png")}
className="w-100"
/>
</div>
<div className="pt-5 pr-2 col">
<div className="d-flex flex-column-reverse">
<h2 className="mb-8 h4 h2-sm">
{translate("XRPL Zone Seoul")}
</h2>
<h6 className="mb-3 eyebrow">{translate("Save the Date")}</h6>
</div>
<p className="mb-4">
{translate(
"Join us at XRPL Zone Seoul where developers, corporates, fintechs, banks, VCs, academia, and the XRP community come together under one roof for the biggest XRPL event in South Korea!"
)}
</p>
<div className=" my-3 event-small-gray">
Location: Seongdong-su, Seoul
</div>
<div className="py-2 my-3 event-small-gray">
September 4th, 2024
</div>
<div className="d-lg-block">
<a
className="btn btn-primary btn-arrow-out"
target="_blank"
href="https://ripple.swoogo.com/xrpl-zone-seoul"
>
{translate("Register Now")}
</a>
</div>
</div>
</div>
</section>
{/* Upcoming Events */}
<section className="container-new py-26" id="upcoming-events">
<div className="p-0 pb-2 mb-4 d-flex flex-column-reverse col-lg-6 pr-lg-5">
<h3 className="h4 h2-sm">
{translate(
"Check out meetups, hackathons, and other events hosted by the XRPL Community"
)}
</h3>
<h6 className="mb-3 eyebrow">{translate("Upcoming Events")}</h6>
</div>
<div className="filter row col-12 mt-lg-5 d-flex flex-column">
<h6 className="mb-3">{translate("Filter By:")}</h6>
<div>
<div className="form-check form-check-inline">
<input
defaultValue="conference"
id="conference-upcoming"
name="conference-upcoming"
type="checkbox"
className="events-filter"
checked={upcomingFilters.conference}
onChange={handleUpcomingFilterChange}
/>
<label htmlFor="conference-upcoming">
{translate("Conference")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="meetup"
id="meetup-upcoming"
name="meetup-upcoming"
type="checkbox"
className="events-filter"
checked={upcomingFilters.meetup}
onChange={handleUpcomingFilterChange}
/>
<label htmlFor="meetup-upcoming">
{translate("Meetups")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="hackathon"
id="hackathon-upcoming"
name="hackathon-upcoming"
type="checkbox"
className="events-filter"
checked={upcomingFilters.hackathon}
onChange={handleUpcomingFilterChange}
/>
<label htmlFor="hackathon-upcoming">
{translate("Hackathons")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="ama"
id="ama-upcoming"
name="ama-upcoming"
type="checkbox"
className="events-filter"
checked={upcomingFilters.ama}
onChange={handleUpcomingFilterChange}
/>
<label htmlFor="ama-upcoming">{translate("AMAs")}</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="cc"
id="cc-upcoming"
name="cc-upcoming"
type="checkbox"
className="events-filter"
checked={upcomingFilters.cc}
onChange={handleUpcomingFilterChange}
/>
<label htmlFor="cc-upcoming">
{translate("Community Calls")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="zone"
id="zone-upcoming"
name="zone-upcoming"
type="checkbox"
className="events-filter"
checked={upcomingFilters.zone}
onChange={handleUpcomingFilterChange}
/>
<label htmlFor="zone-upcoming">
{translate("XRPL Zone")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="info"
id="info-upcoming"
name="info-upcoming"
type="checkbox"
className="events-filter"
checked={upcomingFilters["info"]}
onChange={handleUpcomingFilterChange}
/>
<label htmlFor="info-upcoming">
{translate("Info Session")}
</label>
</div>
</div>
</div>
{/* # Available Types - conference, hackathon, ama, cc, zone, meetup, info */}
<div className="mt-2 row row-cols-1 row-cols-lg-3 card-deck">
{filteredUpcoming.map((event, i) => (
<a
key={event.name + i}
className={`event-card ${event.category[0]}`}
href={event.link}
style={{}}
target="_blank"
>
<div
className="event-card-header"
style={{
background: `url(${event.type.includes('meetup') ? event?.image?.url || imageLookup['meetup'] : imageLookup[event.type[0]]}) no-repeat`,
}}
>
<div className="event-card-title">
{translate(event.name)}
</div>
</div>
<div className="event-card-body">
<p>{translate(event.description)}</p>
</div>
<div className="mt-lg-auto event-card-footer d-flex flex-column">
<span className="mb-2 d-flex icon icon-location">
{event.location}
</span>
<span className="d-flex icon icon-date">{event.date}</span>
</div>
</a>
))}
</div>
</section>
{/* Past Events */}
<section className="container-new pt-26" id="past-events">
<div className="p-0 pb-2 mb-4 d-flex flex-column-reverse col-lg-6 pr-lg-5">
<h3 className="h4 h2-sm">
{translate("Explore past community-hosted events")}
</h3>
<h6 className="mb-3 eyebrow">{translate("Past Events")}</h6>
</div>
<div className="filter row col-12 mt-lg-5 d-flex flex-column">
<h6 className="mb-3">{translate("Filter By:")}</h6>
<div>
<div className="form-check form-check-inline">
<input
defaultValue="conference"
id="conference-past"
name="conference-past"
type="checkbox"
className="events-filter"
checked={pastFilters.conference}
onChange={handlePastFilterChange}
/>
<label htmlFor="conference-past">
{translate("Conference")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="meetup"
id="meetup-past"
name="meetup-past"
type="checkbox"
className="events-filter"
checked={pastFilters.meetup}
onChange={handlePastFilterChange}
/>
<label htmlFor="meetup-past">{translate("Meetups")}</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="hackathon"
id="hackathon-past"
name="hackathon-past"
type="checkbox"
className="events-filter"
checked={pastFilters.hackathon}
onChange={handlePastFilterChange}
/>
<label htmlFor="hackathon-past">
{translate("Hackathons")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="ama"
id="ama-past"
name="ama-past"
type="checkbox"
className="events-filter"
checked={pastFilters.ama}
onChange={handlePastFilterChange}
/>
<label htmlFor="ama-past">{translate("AMAs")}</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="cc"
id="cc-past"
name="cc-past"
type="checkbox"
className="events-filter"
checked={pastFilters.cc}
onChange={handlePastFilterChange}
/>
<label htmlFor="cc-past">
{translate("Community Calls")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="zone"
id="zone-past"
name="zone-past"
type="checkbox"
className="events-filter"
checked={pastFilters.zone}
onChange={handlePastFilterChange}
/>
<label htmlFor="zone-past">{translate("XRPL Zone")}</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="info"
id="info-past"
name="info-past"
type="checkbox"
className="events-filter"
checked={pastFilters["info"]}
onChange={handlePastFilterChange}
/>
<label htmlFor="info-past">{translate("Info Session")}</label>
</div>
</div>
</div>
<div className="mt-2 mb-0 row row-cols-1 row-cols-lg-3 card-deck ">
{filteredPast.map((event, i) => (
<a
key={event.name + i}
className="event-card {event.type}"
href={event.link}
target="_blank"
>
<div
className="event-card-header"
style={{
background: `url(${event.type.includes('meetup') ? event?.image?.url || imageLookup['meetup'] : imageLookup[event.type[0]]}) no-repeat`,
}}
>
<div className="event-card-title">
{translate(event.name)}
</div>
</div>
<div className="event-card-body">
<p>{translate(event.description)}</p>
</div>
<div className="mt-lg-auto event-card-footer d-flex flex-column">
<span className="mb-2 d-flex icon icon-location">
{event.location}
</span>
<span className="d-flex icon icon-date">{event.date}</span>
</div>
</a>
))}
</div>
</section>
<div className="landing page-events">
<div>
<div className="position-relative d-none-sm">
<img
alt="orange waves"
src={require("../static/img/backgrounds/events-orange.svg")}
id="events-orange"
/>
</div>
<section className="text-center py-26">
<div className="mx-auto text-center col-lg-5">
<div className="d-flex flex-column-reverse">
<h1 className="mb-0">
{translate("Find the XRPL Community Around the World")}
</h1>
<h6 className="mb-3 eyebrow">{translate("Events")}</h6>
</div>
</div>
</section>
<section className="container-new py-26">
<div className="event-hero card-grid card-grid-2xN">
<div className="pr-2 col">
<img
alt="xrp ledger apex hero"
src={require("../static/img/events/event-hero3@2x.png")}
className="w-100"
/>
</div>
<div className="pt-5 pr-2 col">
<div className="d-flex flex-column-reverse">
<h2 className="mb-8 h4 h2-sm">
{translate("XRPL Zone Seoul")}
</h2>
<h6 className="mb-3 eyebrow">{translate("Save the Date")}</h6>
</div>
<p className="mb-4">
{translate(
"Join us at XRPL Zone Seoul where developers, corporates, fintechs, banks, VCs, academia, and the XRP community come together under one roof for the biggest XRPL event in South Korea!"
)}
</p>
<div className=" my-3 event-small-gray">
Location: Seongdong-su, Seoul
</div>
<div className="py-2 my-3 event-small-gray">
September 4th, 2024
</div>
<div className="d-lg-block">
<a
className="btn btn-primary btn-arrow-out"
target="_blank"
href="https://ripple.swoogo.com/xrpl-zone-seoul"
>
{translate("Register Now")}
</a>
</div>
</div>
</div>
</section>
{/* Upcoming Events */}
<section className="container-new py-26" id="upcoming-events">
<div className="p-0 pb-2 mb-4 d-flex flex-column-reverse col-lg-6 pr-lg-5">
<h3 className="h4 h2-sm">
{translate(
"Check out meetups, hackathons, and other events hosted by the XRPL Community"
)}
</h3>
<h6 className="mb-3 eyebrow">{translate("Upcoming Events")}</h6>
</div>
<div className="filter row col-12 mt-lg-5 d-flex flex-column">
<h6 className="mb-3">{translate("Filter By:")}</h6>
<div>
<div className="form-check form-check-inline">
<input
defaultValue="conference"
id="conference-upcoming"
name="conference-upcoming"
type="checkbox"
className="events-filter"
checked={upcomingFilters.conference}
onChange={handleUpcomingFilterChange}
/>
<label htmlFor="conference-upcoming">
{translate("Conference")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="meetup"
id="meetup-upcoming"
name="meetup-upcoming"
type="checkbox"
className="events-filter"
checked={upcomingFilters.meetup}
onChange={handleUpcomingFilterChange}
/>
<label htmlFor="meetup-upcoming">
{translate("Meetups")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="hackathon"
id="hackathon-upcoming"
name="hackathon-upcoming"
type="checkbox"
className="events-filter"
checked={upcomingFilters.hackathon}
onChange={handleUpcomingFilterChange}
/>
<label htmlFor="hackathon-upcoming">
{translate("Hackathons")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="ama"
id="ama-upcoming"
name="ama-upcoming"
type="checkbox"
className="events-filter"
checked={upcomingFilters.ama}
onChange={handleUpcomingFilterChange}
/>
<label htmlFor="ama-upcoming">{translate("AMAs")}</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="cc"
id="cc-upcoming"
name="cc-upcoming"
type="checkbox"
className="events-filter"
checked={upcomingFilters.cc}
onChange={handleUpcomingFilterChange}
/>
<label htmlFor="cc-upcoming">
{translate("Community Calls")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="zone"
id="zone-upcoming"
name="zone-upcoming"
type="checkbox"
className="events-filter"
checked={upcomingFilters.zone}
onChange={handleUpcomingFilterChange}
/>
<label htmlFor="zone-upcoming">
{translate("XRPL Zone")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="info"
id="info-upcoming"
name="info-upcoming"
type="checkbox"
className="events-filter"
checked={upcomingFilters["info"]}
onChange={handleUpcomingFilterChange}
/>
<label htmlFor="info-upcoming">
{translate("Info Session")}
</label>
</div>
</div>
</div>
{/* # Available Types - conference, hackathon, ama, cc, zone, meetup, info */}
<div className="mt-2 row row-cols-1 row-cols-lg-3 card-deck">
{filteredUpcoming.map((event, i) => (
<a
key={event.name + i}
className={`event-card ${event.category[0]}`}
href={event.link}
style={{}}
target="_blank"
>
<div
className="event-card-header"
style={{
background: `url(${event.type.includes('meetup') ? event?.image?.url || imageLookup['meetup'] : imageLookup[event.type[0]]}) no-repeat`,
}}
>
<div className="event-card-title">
{translate(event.name)}
</div>
</div>
<div className="event-card-body">
<p>{translate(event.description)}</p>
</div>
<div className="mt-lg-auto event-card-footer d-flex flex-column">
<span className="mb-2 d-flex icon icon-location">
{event.location}
</span>
<span className="d-flex icon icon-date">{event.date}</span>
</div>
</a>
))}
</div>
</section>
{/* Past Events */}
<section className="container-new pt-26" id="past-events">
<div className="p-0 pb-2 mb-4 d-flex flex-column-reverse col-lg-6 pr-lg-5">
<h3 className="h4 h2-sm">
{translate("Explore past community-hosted events")}
</h3>
<h6 className="mb-3 eyebrow">{translate("Past Events")}</h6>
</div>
<div className="filter row col-12 mt-lg-5 d-flex flex-column">
<h6 className="mb-3">{translate("Filter By:")}</h6>
<div>
<div className="form-check form-check-inline">
<input
defaultValue="conference"
id="conference-past"
name="conference-past"
type="checkbox"
className="events-filter"
checked={pastFilters.conference}
onChange={handlePastFilterChange}
/>
<label htmlFor="conference-past">
{translate("Conference")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="meetup"
id="meetup-past"
name="meetup-past"
type="checkbox"
className="events-filter"
checked={pastFilters.meetup}
onChange={handlePastFilterChange}
/>
<label htmlFor="meetup-past">{translate("Meetups")}</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="hackathon"
id="hackathon-past"
name="hackathon-past"
type="checkbox"
className="events-filter"
checked={pastFilters.hackathon}
onChange={handlePastFilterChange}
/>
<label htmlFor="hackathon-past">
{translate("Hackathons")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="ama"
id="ama-past"
name="ama-past"
type="checkbox"
className="events-filter"
checked={pastFilters.ama}
onChange={handlePastFilterChange}
/>
<label htmlFor="ama-past">{translate("AMAs")}</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="cc"
id="cc-past"
name="cc-past"
type="checkbox"
className="events-filter"
checked={pastFilters.cc}
onChange={handlePastFilterChange}
/>
<label htmlFor="cc-past">
{translate("Community Calls")}
</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="zone"
id="zone-past"
name="zone-past"
type="checkbox"
className="events-filter"
checked={pastFilters.zone}
onChange={handlePastFilterChange}
/>
<label htmlFor="zone-past">{translate("XRPL Zone")}</label>
</div>
<div className="form-check form-check-inline">
<input
defaultValue="info"
id="info-past"
name="info-past"
type="checkbox"
className="events-filter"
checked={pastFilters["info"]}
onChange={handlePastFilterChange}
/>
<label htmlFor="info-past">{translate("Info Session")}</label>
</div>
</div>
</div>
<div className="mt-2 mb-0 row row-cols-1 row-cols-lg-3 card-deck ">
{filteredPast.map((event, i) => (
<a
key={event.name + i}
className="event-card {event.type}"
href={event.link}
target="_blank"
>
<div
className="event-card-header"
style={{
background: `url(${event.type.includes('meetup') ? event?.image?.url || imageLookup['meetup'] : imageLookup[event.type[0]]}) no-repeat`,
}}
>
<div className="event-card-title">
{translate(event.name)}
</div>
</div>
<div className="event-card-body">
<p>{translate(event.description)}</p>
</div>
<div className="mt-lg-auto event-card-footer d-flex flex-column">
<span className="mb-2 d-flex icon icon-location">
{event.location}
</span>
<span className="d-flex icon icon-date">{event.date}</span>
</div>
</a>
))}
</div>
</section>
</div>
</ApolloProvider>
</div>
);
}
// App component to wrap everything with ApolloProvider
export default function EventsPageWrapper() {
return (
<ApolloProvider client={client}>
<Events />
</ApolloProvider>
);
}

View File

@@ -0,0 +1,54 @@
import type { PageRouteDetails } from '@redocly/realm/dist/server/plugins/types';
const cache = {
response: null,
expiresAt: 0,
};
async function fetchGql(query: string) {
return fetch(`https://graphql.contentful.com/content/v1/spaces/${process.env.PUBLIC_CONTENTFUL_SPACE_ID}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.CONTENTFUL_ACCESS_TOKEN}`,
},
body: JSON.stringify({ query, variables: {}, operationName: 'GetEvents' }),
}).then(res => res.json());
}
const GET_EVENTS = `
query GetEvents {
eventsCollection {
items {
_id
name
description
category
link
location
startDate
endDate
community
image {
url
}
}
}
}
`;
export default async function getServerProps(route: PageRouteDetails, data: { props: any }) {
try {
if (cache.expiresAt <= Date.now()) {
cache.response = await fetchGql(GET_EVENTS);
cache.expiresAt = Date.now() + 1000 * 60 * 5; // 5 minutes naive cache
}
} catch (e) {
console.error('Failed to fetch events', e);
}
return {
...data.props,
contentfulEvents: cache.response,
};
}

765
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -12,11 +12,10 @@
"keywords": [],
"license": "MIT",
"dependencies": {
"@apollo/client": "^3.11.4",
"@codemirror/state": "6.4.1",
"@codemirror/view": "^6.22.2",
"@lezer/highlight": "^1.2.0",
"@redocly/realm": "0.91.3",
"@redocly/realm": "0.96.0",
"@uiw/codemirror-themes": "4.21.21",
"@uiw/react-codemirror": "^4.21.21",
"@xrplf/isomorphic": "^1.0.0-beta.1",
@@ -37,7 +36,6 @@
"react-dom": "^18.2.0"
},
"devDependencies": {
"@esbuild/darwin-arm64": "^0.23.0",
"bootstrap": "^4.6.2",
"htmltojsx": "^0.3.0",
"sass": "1.26.10"