diff --git a/.github/scripts/fetch-stars.mjs b/.github/scripts/fetch-stars.mjs new file mode 100644 index 00000000..8956d7c6 --- /dev/null +++ b/.github/scripts/fetch-stars.mjs @@ -0,0 +1,40 @@ +import fetch from "node-fetch"; + +const MANIFEST_URL = "https://raw.githubusercontent.com/spicetify/spicetify-themes/generated-manifest/manifest.json"; + +/** + * Get user, repo, and branch from a GitHub raw URL + * @param {string} url Github Raw URL + * @returns { { user: string, repo: string } } + */ +const getParamsFromGithubRaw = (url) => { + const regex_result = url.match(/https:\/\/github\.com\/(?[^/]+)\/(?[^/]+)/); + // e.g. https://github.com/nimsandu/spicetify-bloom + + const obj = { + user: regex_result ? regex_result.groups?.user : null, + repo: regex_result ? regex_result.groups?.repo : null, + }; + + return obj; +}; + +const fetchStars = async () => { + const manifest = await fetch(MANIFEST_URL).then((res) => res.json()); + + const stars = await Promise.all(manifest.map(async (theme) => { + if (!theme.repository) return 'Missing user or repo'; + + const { user, repo } = getParamsFromGithubRaw(theme.repository); + console.log(`Fetching stars for ${user}/${repo}`); + + const url = `https://api.github.com/repos/${user}/${repo}`; + const response = await fetch(url).then((res) => res.json()); + return response.stargazers_count; + })); + + return stars; +}; + +const stars = await fetchStars(); +console.log(stars); diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5c72a669..fd67a656 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,7 +28,7 @@ All types of contributions are encouraged and valued. See the [Table of Contents ## I Have a Question -> If you want to ask a question, we assume that you have read the available [Documentation](). +> If you want to ask a question, we assume that you have read the available [Documentation](https://github.com/spicetify/spicetify-marketplace/wiki). Before you ask a question, it is best to search for existing [Issues](https://github.com/spicetify/spicetify-marketplaceissues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first. @@ -68,7 +68,7 @@ Depending on how large the project is, you may want to outsource the questioning A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible. - Make sure that you are using the latest version. -- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](). If you are looking for support, you might want to check [this section](#i-have-a-question)). +- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://github.com/spicetify/spicetify-marketplace/wiki). If you are looking for support, you might want to check [this section](#i-have-a-question)). - To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/spicetify/spicetify-marketplaceissues?q=label%3Abug). - Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue. - Collect information about the bug: @@ -108,7 +108,7 @@ This section guides you through submitting an enhancement suggestion for Spiceti #### Before Submitting an Enhancement - Make sure that you are using the latest version. -- Read the [documentation]() carefully and find out if the functionality is already covered, maybe by an individual configuration. +- Read the [documentation](https://github.com/spicetify/spicetify-marketplace/wiki) carefully and find out if the functionality is already covered, maybe by an individual configuration. - Perform a [search](https://github.com/spicetify/spicetify-marketplaceissues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. - Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library. diff --git a/package.json b/package.json index 67d8f837..3b95e806 100644 --- a/package.json +++ b/package.json @@ -15,5 +15,8 @@ "packageManager": "yarn@3.2.1", "devDependencies": { "husky": "^8.0.1" + }, + "dependencies": { + "node-fetch": "^3.3.0" } } diff --git a/packages/marketplace/.eslintrc.js b/packages/marketplace/.eslintrc.js index 5518fcd8..8c7eaa5f 100644 --- a/packages/marketplace/.eslintrc.js +++ b/packages/marketplace/.eslintrc.js @@ -49,7 +49,13 @@ module.exports = { "comma-spacing": [ "error", { "before": false, "after": true }, ], + "arrow-parens": [ + "error", "always", + ], "no-trailing-spaces": "error", + "eol-last": [ + "error", "always", + ], "keyword-spacing": "error", "no-multiple-empty-lines": [ "error", { "max": 1 }, diff --git a/packages/marketplace/src/app.tsx b/packages/marketplace/src/app.tsx index 0e00bef2..eda4f7a5 100644 --- a/packages/marketplace/src/app.tsx +++ b/packages/marketplace/src/app.tsx @@ -80,7 +80,7 @@ class App extends React.Component<{ throw new Error("Could not parse marketplace tabs key"); } else if (tabs.length === 0) { throw new Error("Empty marketplace tabs key"); - } else if (tabs.filter(tab => !tab).length > 0) { + } else if (tabs.filter((tab) => !tab).length > 0) { throw new Error("Falsey marketplace tabs key"); } } catch { @@ -120,6 +120,7 @@ class App extends React.Component<{ // of stargazers, and the subscribers_count isn't returned in the main API call we make // https://github.community/t/bug-watchers-count-is-the-duplicate-of-stargazers-count/140865/4 followers: JSON.parse(getLocalStorageDataFromKey("marketplace:followers", false)), + githubTopics: JSON.parse(getLocalStorageDataFromKey("marketplace:githubTopics", false)), }, tabs, activeTab: getLocalStorageDataFromKey(LOCALSTORAGE_KEYS.activeTab, tabs[0]), @@ -130,7 +131,7 @@ class App extends React.Component<{ }, }; - if (!this.CONFIG.activeTab || !this.CONFIG.tabs.filter(tab => tab.name === this.CONFIG.activeTab).length) { + if (!this.CONFIG.activeTab || !this.CONFIG.tabs.filter((tab) => tab.name === this.CONFIG.activeTab).length) { this.CONFIG.activeTab = this.CONFIG.tabs[0].name; } } diff --git a/packages/marketplace/src/components/Card/Card.tsx b/packages/marketplace/src/components/Card/Card.tsx index b735d576..2405abb4 100644 --- a/packages/marketplace/src/components/Card/Card.tsx +++ b/packages/marketplace/src/components/Card/Card.tsx @@ -11,9 +11,7 @@ import { injectUserCSS, generateKey, } from "../../logic/Utils"; -import TrashIcon from "../Icons/TrashIcon"; -import DownloadIcon from "../Icons/DownloadIcon"; -import GitHubIcon from "../Icons/GitHubIcon"; +import { DownloadIcon, GitHubIcon, TrashIcon } from "../Icons"; import { openModal } from "../../logic/LaunchModals"; import AuthorsDiv from "./AuthorsDiv"; import TagsDiv from "./TagsDiv"; @@ -97,7 +95,7 @@ class Card extends React.Component res.json()); + const repoData = await fetch(url).then((res) => res.json()); const { stargazers_count, pushed_at } = repoData; const stateUpdate = { stars: 0, lastUpdated: undefined }; diff --git a/packages/marketplace/src/components/Grid.tsx b/packages/marketplace/src/components/Grid.tsx index 05bd2c7e..e5273476 100644 --- a/packages/marketplace/src/components/Grid.tsx +++ b/packages/marketplace/src/components/Grid.tsx @@ -3,25 +3,25 @@ import { withTranslation } from "react-i18next"; import semver from "semver"; import { Option } from "react-dropdown"; -import { CardItem, CardType, Config, SchemeIni, Snippet, TabItemConfig } from "../types/marketplace-types"; +import { CardItem, CardType, Config, RepoType, SchemeIni, Snippet, TabItemConfig } from "../types/marketplace-types"; import { getLocalStorageDataFromKey, generateSchemesOptions, injectColourScheme, generateKey } from "../logic/Utils"; + import { LOCALSTORAGE_KEYS, ITEMS_PER_REQUEST, MARKETPLACE_VERSION, LATEST_RELEASE } from "../constants"; +import { DownloadIcon, LoadingIcon, LoadMoreIcon, SettingsIcon, ThemeDeveloperToolsIcon } from "./Icons"; import { openModal } from "../logic/LaunchModals"; -import { - getTaggedRepos, - fetchExtensionManifest, fetchThemeManifest, fetchAppManifest, - fetchCssSnippets, getBlacklist, -} from "../logic/FetchRemotes"; -import LoadMoreIcon from "./Icons/LoadMoreIcon"; -import LoadingIcon from "./Icons/LoadingIcon"; -import SettingsIcon from "./Icons/SettingsIcon"; -import ThemeDeveloperToolsIcon from "./Icons/ThemeDeveloperToolsIcon"; import SortBox from "./Sortbox"; import { TopBarContent } from "./TabBar"; import Card from "./Card/Card"; import Button from "./Button"; -import DownloadIcon from "./Icons/DownloadIcon"; import Changelog from "./Modals/Changelog"; +import { + fetchBlacklist, fetchCssSnippets, fetchMonoManifest, + buildExtensionCardData, buildThemeCardData, buildAppCardData, +} from "../logic/FetchRemotes"; +import { + getTaggedRepos, + fetchExtensionManifest, fetchThemeManifest, fetchAppManifest, +} from "../logic/FetchTopicRemotes"; class Grid extends React.Component< { @@ -181,43 +181,7 @@ class Grid extends React.Component< // TODO: maybe we should rename `loadPage()`, since it's slightly confusing when we have github pages as well async loadPage(queue: never[], query?: string) { switch (this.CONFIG.activeTab) { - case "Extensions": { - const pageOfRepos = await getTaggedRepos("spicetify-extensions", this.requestPage, this.BLACKLIST, query); - for (const repo of pageOfRepos.items) { - const extensions = await fetchExtensionManifest( - repo.contents_url, - repo.default_branch, - repo.stargazers_count, - this.CONFIG.visual.hideInstalled, - ); - - // I believe this stops the requests when switching tabs? - if (this.requestQueue.length > 1 && queue !== this.requestQueue[0]) { - // Stop this queue from continuing to fetch and append to cards list - return -1; - } - - if (extensions && extensions.length) { - // console.log(`${repo.name} has ${extensions.length} extensions:`, extensions); - extensions.forEach((extension) => { - Object.assign(extension, { lastUpdated: repo.pushed_at }); - this.appendCard(extension, "extension"); - }); - } - } - - // First result is null or -1 so it coerces to 1 - const currentPage = this.requestPage > -1 && this.requestPage ? this.requestPage : 1; - // Sets the amount of items that have thus been fetched - const soFarResults = ITEMS_PER_REQUEST * (currentPage - 1) + pageOfRepos.page_count; - const remainingResults = pageOfRepos.total_count - soFarResults; - - // If still have more results, return next page number to fetch - console.log(`Parsed ${soFarResults}/${pageOfRepos.total_count} extensions`); - if (remainingResults > 0) return currentPage + 1; - else console.log("No more extension results"); - break; - } case "Installed": { + case "Installed": { const installedStuff = { theme: getLocalStorageDataFromKey(LOCALSTORAGE_KEYS.installedThemes, []), extension: getLocalStorageDataFromKey(LOCALSTORAGE_KEYS.installedExtensions, []), @@ -226,16 +190,17 @@ class Grid extends React.Component< for (const type in installedStuff) { if (installedStuff[type].length) { - installedStuff[type].forEach(async (itemKey) => { + installedStuff[type].forEach(async (itemKey: string) => { // TODO: err handling - const extension = getLocalStorageDataFromKey(itemKey); + // Waits until localStorage is fetched before passing down to the card + const item = await getLocalStorageDataFromKey(itemKey); // I believe this stops the requests when switching tabs? if (this.requestQueue.length > 1 && queue !== this.requestQueue[0]) { // Stop this queue from continuing to fetch and append to cards list return -1; } - this.appendCard(extension, type as CardType); + this.appendCard(item, type as CardType); }); } } @@ -243,71 +208,69 @@ class Grid extends React.Component< // Don't need to return a page number because // installed extension do them all in one go, since it's local - } case "Themes": { - const pageOfRepos = await getTaggedRepos("spicetify-themes", this.requestPage, this.BLACKLIST, query); - for (const repo of pageOfRepos.items) { - - const themes = await fetchThemeManifest( - repo.contents_url, - repo.default_branch, - repo.stargazers_count, - ); - // I believe this stops the requests when switching tabs? - if (this.requestQueue.length > 1 && queue !== this.requestQueue[0]) { - // Stop this queue from continuing to fetch and append to cards list - return -1; - } - - if (themes && themes.length) { - themes.forEach((theme) => { - Object.assign(theme, { lastUpdated: repo.pushed_at }); - this.appendCard(theme, "theme"); - }); - } + } + case "Extensions": + case "Themes": + case "Apps": { + const type = this.CONFIG.activeTab.slice(0, -1).toLowerCase() as RepoType; + let allRepos; + if (this.CONFIG.visual.githubTopics) { + const topicResponse = await getTaggedRepos(`spicetify-${type}s`, this.requestPage, this.BLACKLIST, query); + allRepos = topicResponse.items; + } else { + allRepos = await fetchMonoManifest(type); } - // First request is null, so coerces to 1 - const currentPage = this.requestPage > -1 && this.requestPage ? this.requestPage : 1; - // -1 because the page number is 1-indexed - const soFarResults = ITEMS_PER_REQUEST * (currentPage - 1) + pageOfRepos.page_count; - const remainingResults = pageOfRepos.total_count - soFarResults; + for (const repo of allRepos) { + let cardData: CardItem | CardItem[] | null; + if (this.CONFIG.visual.githubTopics) { + switch (type) { + case "extension": + cardData = await fetchExtensionManifest(repo.contents_url, repo.default_branch, repo.stargazers_count); + break; + case "theme": + cardData = await fetchThemeManifest(repo.contents_url, repo.default_branch, repo.stargazers_count); + break; + case "app": + cardData = await fetchAppManifest(repo.contents_url, repo.default_branch, repo.stargazers_count); + break; + } + } else { + switch (type) { + case "extension": + cardData = buildExtensionCardData(repo); + break; + case "theme": + cardData = buildThemeCardData(repo); + break; + case "app": + cardData = buildAppCardData(repo); + break; + default: + throw new Error(`Unknown type: ${type}`); + } + } - console.log(`Parsed ${soFarResults}/${pageOfRepos.total_count} themes`); - if (remainingResults > 0) return currentPage + 1; - else console.log("No more theme results"); - break; - } case "Apps": { - const pageOfRepos = await getTaggedRepos("spicetify-apps", this.requestPage, this.BLACKLIST, query); - for (const repo of pageOfRepos.items) { - - const apps = await fetchAppManifest( - repo.contents_url, - repo.default_branch, - repo.stargazers_count, - ); + // TODO: do we need this queue stuff any more? // I believe this stops the requests when switching tabs? if (this.requestQueue.length > 1 && queue !== this.requestQueue[0]) { // Stop this queue from continuing to fetch and append to cards list return -1; } - if (apps && apps.length) { - apps.forEach((app) => { - Object.assign(app, { lastUpdated: repo.pushed_at }); - this.appendCard(app, "app"); - }); + if (cardData) { + // console.log(cardData); + if (this.CONFIG.visual.githubTopics) { + for (const item of cardData as CardItem[]) { + Object.assign(item, { lastUpdated: repo.pushed_at }); + this.appendCard(item, type); + } + } else { + this.appendCard(cardData as CardItem, type); + } } } - - // First request is null, so coerces to 1 - const currentPage = this.requestPage > -1 && this.requestPage ? this.requestPage : 1; - // -1 because the page number is 1-indexed - const soFarResults = ITEMS_PER_REQUEST * (currentPage - 1) + pageOfRepos.page_count; - const remainingResults = pageOfRepos.total_count - soFarResults; - - console.log(`Parsed ${soFarResults}/${pageOfRepos.total_count} apps`); - if (remainingResults > 0) return currentPage + 1; - else console.log("No more app results"); + console.log(`Parsed ${this.CONFIG.activeTab.toLowerCase()}`); break; } case "Snippets": { const snippets = await fetchCssSnippets(); @@ -347,7 +310,7 @@ class Grid extends React.Component< } if (this.requestPage === -1) { - this.requestQueue = this.requestQueue.filter(a => a !== queue); + this.requestQueue = this.requestQueue.filter((a) => a !== queue); return; } @@ -410,8 +373,8 @@ class Grid extends React.Component< */ async componentDidMount() { // Checks for new Marketplace updates - fetch(LATEST_RELEASE).then(res => res.json()).then( - result => { + fetch(LATEST_RELEASE).then((res) => res.json()).then( + (result) => { this.setState({ version: result[0].name, }); @@ -422,7 +385,7 @@ class Grid extends React.Component< console.error(err); } }, - error => { + (error) => { console.error("Failed to check for updates", error); }, ); @@ -445,7 +408,7 @@ class Grid extends React.Component< } // Load blacklist - this.BLACKLIST = await getBlacklist(); + this.BLACKLIST = await fetchBlacklist(); this.newRequest(ITEMS_PER_REQUEST); } diff --git a/packages/marketplace/src/components/Icons.tsx b/packages/marketplace/src/components/Icons.tsx new file mode 100644 index 00000000..c382041e --- /dev/null +++ b/packages/marketplace/src/components/Icons.tsx @@ -0,0 +1,55 @@ +import React from "react"; + +export const DownloadIcon = () => ( + +); + +export const GitHubIcon = () => ( + + + +); + +export const LoadingIcon = () => ( + + + + + + + + + + +); + +export class LoadMoreIcon extends React.Component<{onClick: () => void}> { + render() { + return ( +
+

»

+ Load more +
+ ); + } +} + +export const SettingsIcon = () => ( + +); + +export const ThemeDeveloperToolsIcon = () => ( + + + +); + +export const TrashIcon = () => ( + +); diff --git a/packages/marketplace/src/components/Icons/DownloadIcon.tsx b/packages/marketplace/src/components/Icons/DownloadIcon.tsx deleted file mode 100644 index d925b0ea..00000000 --- a/packages/marketplace/src/components/Icons/DownloadIcon.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react"; - -const DownloadIcon = () => { - return ( - - ); -}; - -export default DownloadIcon; diff --git a/packages/marketplace/src/components/Icons/GitHubIcon.tsx b/packages/marketplace/src/components/Icons/GitHubIcon.tsx deleted file mode 100644 index be9b7986..00000000 --- a/packages/marketplace/src/components/Icons/GitHubIcon.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react"; - -// Export GitHub icon SVG as a React component -const GitHubIcon = () => { - return ( - - - - ); -}; -export default GitHubIcon; diff --git a/packages/marketplace/src/components/Icons/LoadMoreIcon.tsx b/packages/marketplace/src/components/Icons/LoadMoreIcon.tsx deleted file mode 100644 index 736441bd..00000000 --- a/packages/marketplace/src/components/Icons/LoadMoreIcon.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from "react"; - -export default class LoadMoreIcon extends React.Component< -{onClick: () => void} -> { - render() { - return ( -
-

»

- Load more -
- ); - } -} diff --git a/packages/marketplace/src/components/Icons/LoadingIcon.tsx b/packages/marketplace/src/components/Icons/LoadingIcon.tsx deleted file mode 100644 index 22c2d191..00000000 --- a/packages/marketplace/src/components/Icons/LoadingIcon.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import React from "react"; - -const LoadingIcon = () => { - // return React.createElement("svg", { - // width: "100px", height: "100px", viewBox: "0 0 100 100", preserveAspectRatio: "xMidYMid", - // }, React.createElement("circle", { - // cx: "50", cy: "50", r: "0", fill: "none", stroke: "currentColor", "stroke-width": "2", - // }, React.createElement("animate", { - // attributeName: "r", repeatCount: "indefinite", dur: "1s", values: "0;40", keyTimes: "0;1", keySplines: "0 0.2 0.8 1", calcMode: "spline", begin: "0s", - // }), React.createElement("animate", { - // attributeName: "opacity", repeatCount: "indefinite", dur: "1s", values: "1;0", keyTimes: "0;1", keySplines: "0.2 0 0.8 1", calcMode: "spline", begin: "0s", - // })), React.createElement("circle", { - // cx: "50", cy: "50", r: "0", fill: "none", stroke: "currentColor", "stroke-width": "2", - // }, React.createElement("animate", { - // attributeName: "r", repeatCount: "indefinite", dur: "1s", values: "0;40", keyTimes: "0;1", keySplines: "0 0.2 0.8 1", calcMode: "spline", begin: "-0.5s", - // }), React.createElement("animate", { - // attributeName: "opacity", repeatCount: "indefinite", dur: "1s", values: "1;0", keyTimes: "0;1", keySplines: "0.2 0 0.8 1", calcMode: "spline", begin: "-0.5s", - // }))); - - return ( - - - - - - - - - - - ); -}; - -export default LoadingIcon; diff --git a/packages/marketplace/src/components/Icons/SettingsIcon.tsx b/packages/marketplace/src/components/Icons/SettingsIcon.tsx deleted file mode 100644 index 1a5f21b4..00000000 --- a/packages/marketplace/src/components/Icons/SettingsIcon.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react"; - -const SettingsIcon = () => { - return ( - - ); -}; - -export default SettingsIcon; diff --git a/packages/marketplace/src/components/Icons/ThemeDeveloperToolsIcon.tsx b/packages/marketplace/src/components/Icons/ThemeDeveloperToolsIcon.tsx deleted file mode 100644 index 0ef63642..00000000 --- a/packages/marketplace/src/components/Icons/ThemeDeveloperToolsIcon.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react"; - -const ThemeDeveloperToolsIcon = () => { - return ( - - - - ); -}; - -export default ThemeDeveloperToolsIcon; diff --git a/packages/marketplace/src/components/Icons/TrashIcon.tsx b/packages/marketplace/src/components/Icons/TrashIcon.tsx deleted file mode 100644 index e74ca1ac..00000000 --- a/packages/marketplace/src/components/Icons/TrashIcon.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react"; - -const TrashIcon = () => { - return ( - - ); -}; - -export default TrashIcon; diff --git a/packages/marketplace/src/components/Modals/BackupModal/index.tsx b/packages/marketplace/src/components/Modals/BackupModal/index.tsx index 66b74ab8..654378dc 100644 --- a/packages/marketplace/src/components/Modals/BackupModal/index.tsx +++ b/packages/marketplace/src/components/Modals/BackupModal/index.tsx @@ -70,8 +70,8 @@ const BackupModal = () => {
setImportText(text)} - highlight={text => highlight(text, languages.css)} + onValueChange={(text) => setImportText(text)} + highlight={(text) => highlight(text, languages.css)} textareaId="marketplace-import-text" textareaClassName="import-textarea" readOnly={false} diff --git a/packages/marketplace/src/components/Modals/Settings/index.tsx b/packages/marketplace/src/components/Modals/Settings/index.tsx index 6615459e..e0cb4444 100644 --- a/packages/marketplace/src/components/Modals/Settings/index.tsx +++ b/packages/marketplace/src/components/Modals/Settings/index.tsx @@ -43,12 +43,13 @@ const SettingsModal = ({ CONFIG, updateAppConfig } : Props) => { return (

{t("settings.optionsHeading")}

- - - - - -

{t("settings.tabsHeading")}

+ + + + + + +

Tabs

{modalConfig.tabs.map(({ name }, index) => { return ; diff --git a/packages/marketplace/src/components/Modals/Snippet/index.tsx b/packages/marketplace/src/components/Modals/Snippet/index.tsx index c055e311..d4e2296a 100644 --- a/packages/marketplace/src/components/Modals/Snippet/index.tsx +++ b/packages/marketplace/src/components/Modals/Snippet/index.tsx @@ -93,8 +93,8 @@ const SnippetModal = (props: { content?: CardProps, type: ModalType, callback?:
setCode(code)} - highlight={code => highlight(code, languages.css)} + onValueChange={(code) => setCode(code)} + highlight={(code) => highlight(code, languages.css)} textareaId="marketplace-custom-css" textareaClassName="snippet-code-editor" readOnly={props.type === "VIEW_SNIPPET"} @@ -133,7 +133,7 @@ const SnippetModal = (props: { content?: CardProps, type: ModalType, callback?: {t("snippets.snippetPreview")} { props.type !== "VIEW_SNIPPET" && `(${t("snippets.optional")})` } {imageURL && -