Merge pull request #163 from storytold/bt-bflat-fy-rating

user ratings, yarn upgrade, fontawesome pro
This commit is contained in:
Brandon Thomas authored and GitHub committed 2023-01-26 03:54:07 -05:00
commit 5df29162c7
20 files changed
+20713 -14647

No files matched your search

+9
View File
@@ -0,0 +1,9 @@
nodeLinker: node-modules
npmScopes:
fortawesome:
npmAlwaysAuth: true
npmAuthToken: 104779DB-FD41-4BEA-BDB4-B1845D758A79
npmRegistryServer: "https://npm.fontawesome.com/"
yarnPath: .yarn/releases/yarn-3.3.1.cjs
+2 -1
View File
@@ -31,5 +31,6 @@
"dependencies": {
"react-select": "^5.7.0",
"yarn": "^1.22.19"
}
},
"packageManager": "yarn@3.3.1"
}
@@ -20,6 +20,7 @@ export interface TtsModel {
is_front_page_featured: boolean,
is_twitch_featured: boolean,
maybe_suggested_unique_bot_command: string | null,
user_ratings: UserRatings,
creator_set_visibility: string,
updatable_slug: string,
created_at: string,
@@ -36,6 +37,13 @@ export interface CustomVocoderFields {
creator_gravatar_hash: string,
}
export interface UserRatings {
positive_count: number,
negative_count: number,
// Total count does not take into account "neutral" ratings.
total_count: number,
}
export interface TtsModelModeratorFields {
creator_is_banned: boolean,
creator_ip_address_creation: string,
@@ -18,11 +18,19 @@ export interface TtsModelListItem {
title: string,
is_front_page_featured: boolean,
is_twitch_featured: boolean,
user_ratings: UserRatings,
category_tokens: string[],
created_at: string,
updated_at: string,
}
export interface UserRatings {
positive_count: number,
negative_count: number,
// Total count does not take into account "neutral" ratings.
total_count: number,
}
export async function ListTtsModels() : Promise<Array<TtsModelListItem>| undefined> {
const endpoint = new ApiConfig().listTts();
+4 -4
View File
@@ -3,12 +3,12 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@storyteller/components": "0.1.0",
"@craco/craco": "^6.4.3",
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-brands-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/fontawesome-svg-core": "^6.2.1",
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@storyteller/components": "0.1.0",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^13.5.0",
+10 -4
View File
@@ -3,14 +3,19 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@storyteller/components": "0.1.0",
"@colormap/core": "0.1.0-3",
"@colormap/presets": "0.1.0-4",
"@craco/craco": "^6.4.3",
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-brands-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/fontawesome-common-types": "^6.2.1",
"@fortawesome/fontawesome-svg-core": "^6.2.1",
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/pro-duotone-svg-icons": "^6.2.1",
"@fortawesome/pro-light-svg-icons": "^6.2.1",
"@fortawesome/pro-regular-svg-icons": "^6.2.1",
"@fortawesome/pro-solid-svg-icons": "^6.2.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@storyteller/components": "0.1.0",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
@@ -32,6 +37,7 @@
"howler": "^2.2.0",
"i18next": "^21.6.11",
"js-cookie": "^3.0.1",
"pretty-num": "^0.5.2",
"query-string": "^8.1.0",
"react": "^16.13.1",
"react-autocomplete": "^1.8.1",
+1 -1
View File
@@ -119,7 +119,7 @@ $headings-font-family: "Merriweather", serif;
.nav-link {
font-size: 15px;
font-weight: 600;
font-weight: 500;
padding-left: 16px !important;
padding-right: 16px !important;
color: $light-text-color;
+5
View File
@@ -0,0 +1,5 @@
// pretty-num.d.ts
declare module "pretty-num" {
export function prettyNum(...args: any[]): number;
export const ROUNDING_MODE: any;
}
@@ -10,6 +10,7 @@ styles with important tags:
// makes it impossible to dynamically change styles.
//
// Once the rollout is complete, this outer wrapper class can be removed.
.fakeyou-refresh {
p {
font-weight: 300;
@@ -172,7 +173,7 @@ styles with important tags:
border-radius: 5px;
outline: none;
font-size: 15px;
font-weight: 600;
font-weight: 500;
padding: 10px 24px;
z-index: 2;
display: flex;
@@ -661,11 +662,11 @@ styles with important tags:
background-color: lighten($panel, 4%);
border: 1px solid #39394c;
border-radius: 5px;
padding: 11px 16px;
padding: 16px 20px;
&:hover {
border-color: lighten(#39394c, 10%);
}
// &:hover {
// border-color: lighten(#39394c, 10%);
// }
}
.input-icon-search {
@@ -782,6 +783,51 @@ styles with important tags:
.result-text {
font-size: 18px;
}
.btn-rate {
font-weight: 500;
font-size: 17px;
background-color: lighten($secondary, 4%);
border-radius: 50px;
border: none;
padding: 6px 20px;
color: rgba($white, 0.5);
transition: 0.1s all;
&.left {
border-radius: 50px 0px 0px 50px;
}
&.right {
border-radius: 0px 50px 50px 5px;
}
&.rated {
color: $white;
background-color: lighten($secondary, 15%);
}
&:hover {
background-color: lighten($secondary, 10%);
}
}
.rating-icon {
color: #ffbc39;
&.heart {
color: $primary;
}
}
.tippy-box[data-theme~="fakeyou"] {
background-color: lighten($secondary, 5%);
color: $white;
}
.tippy-box[data-theme~="fakeyou"] > .tippy-svg-arrow {
fill: lighten($secondary, 5%);
}
}
select {
@@ -11,7 +11,7 @@ interface Props {
function BackLink(props: Props) {
const linkText = props.text === undefined ? "Back" : props.text;
return (
<Link to={props.link}>
<Link to={props.link} className="fw-medium">
<FontAwesomeIcon icon={faArrowLeft} />
<span className="ms-2">{linkText}</span>
</Link>
@@ -0,0 +1,117 @@
import React, { useState, useCallback, useEffect } from "react";
import { GetUserRating, GetUserRatingIsOk } from "@storyteller/components/src/api/user_ratings/GetUserRating";
import { SetUserRating, SetUserRatingIsOk } from "@storyteller/components/src/api/user_ratings/SetUserRating";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faThumbsDown,
faThumbsUp,
} from "@fortawesome/free-solid-svg-icons";
import Tippy from "@tippyjs/react";
import "tippy.js/dist/tippy.css";
interface Props {
entity_type: string;
entity_token: string;
}
/**
* This is a reusable component that can be put on several different pages.
*
* It requires the entity type ("tts_model", "tts_result", "w2l_template", "w2l_result", etc.)
* and the entity token, and it will be able to fetch a user's previous vote and change it.
*
* This button component manages all of its own state and API calls.
*/
function RatingButtons(props: Props) {
const [userRatingValue, setUserRatingValue] = useState<string|undefined>(undefined);
const loadRating = useCallback(async () => {
const request = {
entity_type: props.entity_type,
entity_token: props.entity_token,
};
const rating = await GetUserRating(request);
if (GetUserRatingIsOk(rating)) {
let ratingValue = rating.maybe_rating_value || undefined;
setUserRatingValue(ratingValue);
}
}, [
setUserRatingValue,
props.entity_type,
props.entity_token,
]);
const toggleUpvote = async () => {
let nextValue = userRatingValue === "positive" ? "neutral" : "positive";
await setRating(nextValue);
};
const toggleDownvote = async () => {
let nextValue = userRatingValue === "negative" ? "neutral" : "negative";
await setRating(nextValue);
};
const setRating = async (ratingValue: string) => {
const request = {
entity_type: props.entity_type,
entity_token: props.entity_token,
rating_value: ratingValue,
};
const result = await SetUserRating(request);
if (SetUserRatingIsOk(result)) {
setUserRatingValue(ratingValue);
loadRating();
}
};
useEffect(() => {
loadRating();
}, [loadRating, props.entity_token]);
let upClasses = "btn-rate left";
let downClasses = "btn-rate right";
if (userRatingValue === "positive") {
upClasses += " rated";
} else if (userRatingValue === "negative") {
downClasses += " rated";
}
return (
<div className="d-flex">
<Tippy
content="This voice sounds good"
hideOnClick
placement="bottom"
theme="fakeyou"
arrow={false}
>
<button
className={upClasses}
onClick={toggleUpvote}
>
<FontAwesomeIcon icon={faThumbsUp} />
</button>
</Tippy>
<div className="vr"></div>
<Tippy
content="This voice sounds bad"
hideOnClick
placement="bottom"
theme="fakeyou"
arrow={false}
>
<button
className={downClasses}
onClick={toggleDownvote}
>
<FontAwesomeIcon icon={faThumbsDown} />
</button>
</Tippy>
</div>
)
}
export { RatingButtons };
@@ -0,0 +1,66 @@
import React from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faFrown,
faStar,
faStarHalfAlt,
} from "@fortawesome/free-solid-svg-icons";
import {
faStarExclamation,
} from "@fortawesome/pro-duotone-svg-icons";
import { prettyNum, ROUNDING_MODE } from "pretty-num";
interface Props {
positive_votes: number,
negative_votes: number,
// Total votes should equal (positive_votes + negative_votes).
// It does not include "neutral" votes, where the user revokes their vote.
total_votes: number,
}
function RatingStats(props: Props) {
if (props.total_votes === 0
|| (props.positive_votes === 0 && props.negative_votes === 0)
) {
return (
<div className="d-flex align-items-center">
<FontAwesomeIcon icon={faStarExclamation} className="me-2 rating-icon" />
<p>
Voice Not Yet Rated
</p>
</div>
);
}
// Rating scale: 0 to 5, with one decimal digit.
let score = (props.positive_votes / props.total_votes) * 5.0;
let scoreRounded = prettyNum(score, {precision: 1, roundingMode: ROUNDING_MODE.CEIL});
let scoreTitle;
let icon;
if (scoreRounded >= 4.0) {
scoreTitle = "Voice Sounds Great";
icon = faStar;
} else if (scoreRounded >= 3.0) {
scoreTitle = "Voice Sounds Good";
icon = faStar;
} else if (scoreRounded >= 2.0) {
scoreTitle = "Voice Sounds Okay";
icon = faStarHalfAlt;
} else {
scoreTitle = "Voice Sounds Meh";
icon = faFrown;
}
return (
<div className="d-flex align-items-center">
<FontAwesomeIcon icon={icon} className="me-2 rating-icon" />
<p>
Rating: <span className="fw-medium">{scoreRounded} — {scoreTitle}</span>
</p>
</div>
)
}
export { RatingStats };
@@ -37,8 +37,8 @@ import { TwitchTtsNotice } from "./notices/TwitchTtsNotice";
import { PleaseFollowNotice } from "./notices/PleaseFollowNotice";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faArrowRight,
faBarsStaggered,
faChevronRight,
faCompass,
faDeleteLeft,
faGlobe,
@@ -67,6 +67,8 @@ import {
import { ExploreVoicesModal } from "./explore/ExploreVoicesModal";
import { WebUrl } from "../../../../../common/WebUrl";
import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle";
import { RatingButtons } from "../../../_common/ratings/RatingButtons";
import { RatingStats } from "../../../_common/ratings/RatingStats";
export interface EnqueueJobResponsePayload {
success: boolean;
@@ -326,15 +328,9 @@ function TtsModelListPage(props: Props) {
] || ENGLISH_LANGUAGE;
directViewLink = (
<Link
to={modelLink}
onClick={() => {
Analytics.ttsClickModelDetailsLink();
}}
className="d-flex flex-column flex-lg-row gap-3 direct-view-link zi-2 align-items-lg-center mb-4"
>
<div className="flex-grow-1">
<p>
<div className="d-flex flex-column direct-view-link zi-2 mb-4">
<div className="d-flex flex-column gap-3 flex-lg-row">
<p className="flex-grow-1">
{t("tts.TtsModelListPage.voiceDetails.voiceBy")}{" "}
<Link
to={profileLink}
@@ -352,16 +348,42 @@ function TtsModelListPage(props: Props) {
</Link>{" "}
| <FontAwesomeIcon icon={faGlobe} className="me-2" />
{t("tts.TtsModelListPage.languageLabel")}:{" "}
<span className="fw-semibold">{modelLanguage.languageName}</span>{" "}
<span className="fw-medium">{modelLanguage.languageName}</span>{" "}
{/* We're not ready for use count yet. */}
{/*| Use count:{" "}
<span className="fw-semibold">616400</span>*/}
<span className="fw-semibold">616400</span> -- the old one*/}
{/*| Used <span className="fw-medium">308,270 times</span> -- the new one */}
</p>
<Link
to={modelLink}
onClick={() => {
Analytics.ttsClickModelDetailsLink();
}}
className="d-flex align-items-center"
>
<span className="fw-medium">
{t("tts.TtsModelListPage.voiceDetails.seeMoreDetails")}
</span>
<FontAwesomeIcon icon={faArrowRight} className="ms-2" />
</Link>
</div>
<div className="fw-medium">
<span>{t("tts.TtsModelListPage.voiceDetails.seeMoreDetails")}</span>
<FontAwesomeIcon icon={faChevronRight} className="ms-2" />
<hr />
<div className="d-flex gap-3">
<RatingButtons
entity_type="tts_model"
entity_token={maybeSelectedTtsModel?.model_token || ""}
/>
<RatingStats
positive_votes={maybeSelectedTtsModel?.user_ratings?.positive_count || 0}
negative_votes={maybeSelectedTtsModel?.user_ratings?.negative_count || 0 }
total_votes={maybeSelectedTtsModel?.user_ratings?.total_count || 0}
/>
</div>
</Link>
</div>
);
}
@@ -62,6 +62,8 @@ import {
} from "react-share";
import { Analytics } from "../../../../../common/Analytics";
import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle";
import { RatingButtons } from "../../../_common/ratings/RatingButtons";
import { RatingStats } from "../../../_common/ratings/RatingStats";
interface Props {
sessionWrapper: SessionWrapper;
@@ -92,7 +94,10 @@ function TtsModelViewPage(props: Props) {
const [notFoundState, setNotFoundState] = useState<boolean>(false);
const documentTitle = ttsModel?.title === undefined ? undefined : `${ttsModel.title} Deep Fake TTS generator`;
const documentTitle =
ttsModel?.title === undefined
? undefined
: `${ttsModel.title} Deep Fake TTS generator`;
usePrefixedDocumentTitle(documentTitle);
const getModel = useCallback(async (token) => {
@@ -160,9 +165,7 @@ function TtsModelViewPage(props: Props) {
listAllTtsCategories,
]);
const shareLink = `https://fakeyou.com${WebUrl.ttsModelPage(
token
)}`;
const shareLink = `https://fakeyou.com${WebUrl.ttsModelPage(token)}`;
const shareTitle = `Use FakeYou to generate speech as ${
ttsModel?.title || "your favorite characters"
}!`;
@@ -255,9 +258,7 @@ function TtsModelViewPage(props: Props) {
let creatorLink = <span />;
if (!!ttsModel?.creator_display_name) {
const creatorUrl = WebUrl.userProfilePage(
ttsModel?.creator_username
);
const creatorUrl = WebUrl.userProfilePage(ttsModel?.creator_username);
creatorLink = (
<span>
<Gravatar
@@ -325,10 +326,7 @@ function TtsModelViewPage(props: Props) {
deleteModelButton = (
<>
<Link
className={deleteButtonCss}
to={WebUrl.ttsModelDeletePage(token)}
>
<Link className={deleteButtonCss} to={WebUrl.ttsModelDeletePage(token)}>
<FontAwesomeIcon icon={faTrash} className="me-2" />
{deleteButtonTitle}
</Link>
@@ -667,8 +665,22 @@ function TtsModelViewPage(props: Props) {
<motion.h1 className="display-5 fw-bold mb-3" variants={item}>
{title}
</motion.h1>
{/* Rate Voice Model Buttons */}
<div className="d-flex gap-3">
<RatingButtons
entity_type="tts_model"
entity_token={ttsModel?.model_token || ""}
/>
<RatingStats
positive_votes={ttsModel?.user_ratings?.positive_count || 0}
negative_votes={ttsModel?.user_ratings?.negative_count || 0 }
total_votes={ttsModel?.user_ratings?.total_count || 0}
/>
</div>
</div>
<motion.div className="mb-4" variants={item}>
<motion.div className="mb-3 mt-4 pt-2" variants={item}>
<BackLink link="/" text="Back to all models" />
</motion.div>
</div>
@@ -23,6 +23,9 @@ import {
faEye,
faEyeSlash,
faUser,
faThumbsUp,
faThumbsDown,
faHeart,
} from "@fortawesome/free-solid-svg-icons";
import { motion } from "framer-motion";
import { container, item, panel } from "../../../../../data/animation";
@@ -40,6 +43,8 @@ import {
import { BackLink } from "../../../_common/BackLink";
import { TextExpander } from "../../../_common/TextExpander";
import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle";
import Tippy from "@tippyjs/react";
import "tippy.js/dist/tippy.css";
interface Props {
sessionWrapper: SessionWrapper;
@@ -270,7 +275,7 @@ function TtsResultViewPage(props: Props) {
ttsInferenceResult.tts_model_title !== null
) {
headingTitle = `${ttsInferenceResult.tts_model_title}`;
subtitle = <h1 className="panel-title fw-bold">TTS Result</h1>;
subtitle = <h2 className="panel-title fw-bold">TTS Result</h2>;
}
const currentlyDeleted =
@@ -436,11 +441,47 @@ function TtsResultViewPage(props: Props) {
<motion.h1 className="display-5 fw-bold mb-3" variants={item}>
{headingTitle}
</motion.h1>
{/* Rate Result Buttons */}
<div className="d-flex gap-3">
<div className="d-flex">
<Tippy
content="I like this audio"
hideOnClick
placement="bottom"
theme="fakeyou"
arrow={false}
>
<button className="btn-rate left rated">
<FontAwesomeIcon icon={faThumbsUp} />
</button>
</Tippy>
<motion.div className="mb-4 pb-2" variants={item}>
<BackLink link="/" text="Back to all models" />
</motion.div>
<motion.p className="mb-3 result-text">
<div className="vr"></div>
<Tippy
content="I dislike this audio"
hideOnClick
placement="bottom"
theme="fakeyou"
arrow={false}
>
<button className="btn-rate right">
<FontAwesomeIcon icon={faThumbsDown} />
</button>
</Tippy>
</div>
<div className="d-flex align-items-center">
<FontAwesomeIcon
icon={faHeart}
className="me-2 rating-icon heart"
/>
<p>
<span className="fw-medium">1,518 likes</span>
</p>
</div>
</div>
<motion.p className="mb-3 result-text mt-4 pt-2">
<TextExpander text={ttsInferenceResult.raw_inference_text} />
</motion.p>
</div>
+7 -7
View File
@@ -3,12 +3,12 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@storyteller/components": "0.1.0",
"@craco/craco": "^6.4.3",
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-brands-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/fontawesome-svg-core": "^6.2.1",
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@storyteller/components": "0.1.0",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^13.5.0",
@@ -23,10 +23,10 @@
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"react-scripts": "5.0.0",
"typescript": "^4.5.5",
"web-vitals": "^2.1.4",
"react-wavesurfer.js": "^0.0.5",
"wavesurfer.js": "^6.2.0"
"typescript": "^4.5.5",
"wavesurfer.js": "^6.2.0",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "craco start",
+4 -4
View File
@@ -3,12 +3,12 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@storyteller/components": "0.1.0",
"@craco/craco": "^6.4.3",
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-brands-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/fontawesome-svg-core": "^6.2.1",
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@storyteller/components": "0.1.0",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^13.5.0",
+7 -7
View File
@@ -3,12 +3,12 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@storyteller/components": "0.1.0",
"@craco/craco": "^6.4.3",
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-brands-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/fontawesome-svg-core": "^6.2.1",
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@storyteller/components": "0.1.0",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^13.5.0",
@@ -23,10 +23,10 @@
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"react-scripts": "5.0.0",
"typescript": "^4.5.5",
"web-vitals": "^2.1.4",
"react-wavesurfer.js": "^0.0.8",
"wavesurfer.js": "^6.2.0"
"typescript": "^4.5.5",
"wavesurfer.js": "^6.2.0",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "craco start",
+14 -14
View File
@@ -3,16 +3,17 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@storyteller/components": "0.1.0",
"@craco/craco": "^6.4.3",
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-brands-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@formspree/react": "^2.4.0",
"@fortawesome/fontawesome-svg-core": "^6.2.1",
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@storyteller/components": "0.1.0",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^13.5.0",
"@tippyjs/react": "^4.2.6",
"@types/jest": "^27.4.0",
"@types/node": "^16.11.21",
"@types/react": "^16.9.36",
@@ -21,22 +22,21 @@
"bulma": "^0.9.0",
"craco": "^0.0.3",
"file": "^0.2.2",
"gsap": "^3.11.0",
"locomotive-scroll": "^4.1.4",
"react": "^16.13.1",
"react-autocomplete": "^1.8.1",
"react-dom": "^16.13.1",
"react-fast-marquee": "^1.3.5",
"react-locomotive-scroll": "^0.2.2",
"react-router-dom": "^5.2.0",
"react-scripts": "5.0.0",
"three": "0.138.3",
"typescript": "^4.5.5",
"web-vitals": "^2.1.4",
"locomotive-scroll": "^4.1.4",
"react-locomotive-scroll": "^0.2.2",
"react-fast-marquee": "^1.3.5",
"@tippyjs/react": "^4.2.6",
"gsap": "^3.11.0",
"react-toastify": "^9.0.8",
"split-type": "^0.3.2",
"swiper": "^8.3.2",
"react-toastify": "^9.0.8"
"three": "0.138.3",
"typescript": "^4.5.5",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "craco start",
+20291 -14566
View File
File diff suppressed because it is too large. Load diff